#include "QbMessageProcess.h"

#include <bondlib/BondContainer.h>
#include <core/Utility.h>
#include <core/sharedata/login_data.h>
#include <core/strings/string_convert.h>
#include <core/time/system_time.h>
#include <qbkernel/include/qb_base.h>
#include <qbprotocol/include/MessageParserTool.h>
#include <qbprotocol/include/SSIDBModel.h>
#include <qbprotocol/include/SSQBAModel.h>
#include <qbprotocol/include/SSQBModel.h>
#include <qbprotocol/include/rdMessage.h>
#include <qbprotocol/include/rdProto.h>
#include <qbtools/message/MessagePoster.h>
#include <uam/ServerTimeMgr.h>
#include <uam/UserAccountManager.h>

using namespace qb;

#define Reg_Func(ID) \
  qbBase::getMessageBond()->RegisterDecodeFunc(ID, qbbond::ExtracFunc)
#define DelPtr(FUNC, TYPE)               \
  case FUNC: {                           \
    TYPE* p = static_cast<TYPE*>(toDel); \
    delete p;                            \
    return nullptr;                      \
  } break;

#define DECODE_RAWHEAD                                                   \
  static char sBuffer[Y_RD_SERVICE_MESSAGE_BLOCK_LEN] = {0};             \
  int nLenOut = 0;                                                       \
  if (!rdMessage::bUnZip((char*)rawvalue.Data, rawvalue.Length, sBuffer, \
                         &nLenOut))                                      \
    return nullptr;                                                      \
  /*按照字典格式解析数据*/                                     \
  char* sFileBuffer = sBuffer;                                           \
  size_t nStartPos, record_cnt, nFieldCnt;                               \
  nStartPos = record_cnt = nFieldCnt = 0;                                \
  std::vector<std::string> vHeaders;                                     \
  /*parse headers*/                                                      \
  std::string str;                                                       \
  memcpy_s(&nStartPos, sizeof(unsigned int), sFileBuffer + 4, 4);        \
  memcpy_s(&record_cnt, sizeof(unsigned int), sFileBuffer + 8, 4);       \
  memcpy_s(&nFieldCnt, sizeof(unsigned int), sFileBuffer + 12, 2);       \
  sFileBuffer += 14;                                                     \
  vHeaders.reserve(nFieldCnt);                                           \
  for (int i = 0; i != nFieldCnt; ++i) {                                 \
    str = sFileBuffer;                                                   \
    sFileBuffer = sFileBuffer + str.length() + 2;                        \
    vHeaders.emplace_back(str);                                          \
  }                                                                      \
  sFileBuffer = sFileBuffer + 8;

void qbbond::InitDecodeFuncs() {
  Reg_Func(E_FID_QB_HIS_SINGLE_DEAL_REG);
  Reg_Func(E_FID_QB_HIS_SINGLE_DEAL_REQ);
  Reg_Func(E_FID_QB_HIS_SINGLE_DEAL_UNREG);
  Reg_Func(E_FID_QB_BOND_GRADE_INSTITUTION_REQ);
  Reg_Func(E_FID_QB_BOND_CDC_SPECIAL_INFO);
  Reg_Func(E_FID_QBA_CDC_PRICE_ALL_REQ_V3);
  Reg_Func(E_FID_QBA_CDC_PRICE_SPECIAL_REQ);
  Reg_Func(E_FID_QB_BEST_PRICE_REQ);
  Reg_Func(E_FID_QB_BEST_PRICE_PUSH_V2);
  Reg_Func(E_FID_QB_MARKET_STREAM_REQ);
  Reg_Func(E_FID_QB_EX_MARKETSTREAM_QUERY_NEW);
  Reg_Func(E_FID_QB_CFETS_MARKET_STREAM_REQ);
  Reg_Func(E_FID_QB_CFETS_MARKET_STREAM_REQ_NEW);
  Reg_Func(E_FID_QB_MARKET_STREAM_DEAL_REQ);
  Reg_Func(E_FID_QB_MARKET_STREAM_DEAL_PUSH);
  Reg_Func(E_FID_QB_MARKET_STREAM_BY_GROUP_QRY);
  Reg_Func(E_FID_QB_CFETS_DEAL_PUSH);
  Reg_Func(E_FID_QB_CFETS_MARKET_STREAM_DEAL_REQ);
  Reg_Func(E_FID_QB_EX_MARKETSTREAM_PUSH);
  Reg_Func(E_FID_QB_EX_DEAL_QUERY);
  Reg_Func(E_FID_QB_EX_DEAL_PUSH_V2);
  Reg_Func(E_FID_QB_EX_DEAL_PUSH);
  Reg_Func(E_FID_QBA_BROKER_DEAL_KLINE_DAY_CLOSE_REQ);
  Reg_Func(E_FID_QBA_BROKER_KLINE_DAY_CLOSE_REQ);
  Reg_Func(E_FID_QB_CFETS_DEAL_DAYLINE_QUERY);
  Reg_Func(E_FID_QBA_BROKER_DEAL_KLINE_DAY_REQ);
  Reg_Func(E_FID_QBA_YIELD_CURVE_REQ_V2);
  Reg_Func(E_FID_QB_ISSUER_CREDIT_SPREAD_REQ);
  Reg_Func(E_FID_QB_BOND_CREDIT_SPREAD_REQ);
  Reg_Func(E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V2);
  Reg_Func(E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V3);
  Reg_Func(E_FID_QB_CFETS_MARKETMAKER_QUOTE_QUERY);
  Reg_Func(E_FID_QB_CFETS_MARKETMAKER_QUOTE_PUSH);
  Reg_Func(E_FID_QB_CFETS_XBOND_QUOTE_QUERY);
  Reg_Func(E_FID_QB_CFETS_XBOND_QUOTE_PUSH);
  Reg_Func(E_FID_QB_BESTPRICE_SYNTHETICAL_REQ);
  Reg_Func(E_FID_QB_BESTPRICE_SYNTHETICAL_PUSH);
  Reg_Func(E_FID_QB_BESTPRICE_SYNTHETICAL_PUSH_CANCEL);
  Reg_Func(E_FID_CSI_PRICE_ALL_REQ_V2);
  Reg_Func(E_FID_QB_BOND_LIQUIDITY_FULL_REQ_V2);
  Reg_Func(E_FID_QB_ISSUER_LIQUIDITY_FULL_REQ_V2);
  Reg_Func(E_FID_QB_HIGT_YIELD_BOND_QRY);
  Reg_Func(E_FID_QB_THIRD_PARTY_GUARANTEE_QRY);
  Reg_Func(E_FID_QB_SECTOR_BOND_REQ);
  Reg_Func(E_FID_MARKETMAKE_TARGET_BOND_REQ);
  Reg_Func(E_FID_QB_BOND_SS_INFO_NEW);
  Reg_Func(E_FID_QB_BOND_SS_ISSUER_INFO_NEW);
  Reg_Func(E_FID_QB_EX_BEST_QUOTE_PUSH);
  Reg_Func(E_FID_QB_EX_BEST_QUOTE_PUSH_CANCEL);
  Reg_Func(E_FID_QB_EX_BEST_QUOTE_QUERY);
  Reg_Func(E_FID_QB_EX_QUOTE_QUERY);
  Reg_Func(E_FID_QB_EX_QUOTE_PUSH_V2);
  Reg_Func(E_FID_QB_EX_QUOTE_PUSH_CANCEL);
  Reg_Func(E_FID_QB_SHFI_SINGLE_QUOTE_PUSH);
  Reg_Func(E_FID_QB_SHFI_SINGLE_QUOTE_PUSH_CANCEL);
  Reg_Func(E_FID_QB_SHFI_SINGLE_QUOTE_REQ);
  Reg_Func(E_FID_QB_COMPANY_SORT_REQ);
  Reg_Func(E_FID_QB_MIXED_BESTQUOTE_REQ);
  Reg_Func(E_FID_QB_MIXED_BESTQTUOE_PUSH);
  Reg_Func(E_FID_QB_ABBOND_RECOMMEND_PRICE_REQ);
  Reg_Func(E_FID_QB_ABBOND_RECOMMEND_PRICE_PUSH);
  Reg_Func(E_FID_QB_ABBOND_RECOMMEND_PRICE_PUSH_CANCEL);
}

static void* delAck(int func, void* toDel) {
  switch (func) {
    DelPtr(E_FID_QB_HIS_SINGLE_DEAL_REG, xSingleBondQuotationAck_c);
    DelPtr(E_FID_QB_HIS_SINGLE_DEAL_REQ, xSingleBondQuotationAck_c);
    DelPtr(E_FID_QB_BOND_GRADE_INSTITUTION_REQ, xQBBondGradeInstitutionAck);
    DelPtr(E_FID_QB_BOND_CDC_SPECIAL_INFO, xQBBondCDCSpecialInfoListAck_c);
    DelPtr(E_FID_QBA_CDC_PRICE_ALL_REQ_V3, xQBACDCPriceList_c);
    DelPtr(E_FID_QBA_CDC_PRICE_SPECIAL_REQ, xQBACDCPriceList_c);
    DelPtr(E_FID_QB_BEST_PRICE_REQ, xQBBestPriceListAck_c);
    DelPtr(E_FID_QB_MARKET_STREAM_REQ, xQBMarketStreamList_c);
    DelPtr(E_FID_QB_EX_MARKETSTREAM_QUERY_NEW, xQBMarketStreamList_c);
    DelPtr(E_FID_QB_CFETS_MARKET_STREAM_REQ, xQBMarketStreamList_c);
    DelPtr(E_FID_QB_CFETS_MARKET_STREAM_REQ_NEW, xQBMarketStreamList_c);
    DelPtr(E_FID_QB_MARKET_STREAM_DEAL_REQ, xQBMarketStreamList_c);
    DelPtr(E_FID_QB_MARKET_STREAM_DEAL_PUSH, xQBMarketStreamList_c);
    DelPtr(E_FID_QB_MARKET_STREAM_BY_GROUP_QRY, xQBMarketStreamList_c);
    DelPtr(E_FID_QB_CFETS_DEAL_PUSH, xQBMarketStreamList_c);
    DelPtr(E_FID_QB_CFETS_MARKET_STREAM_DEAL_REQ, xQBMarketStreamList_c);
    DelPtr(E_FID_QB_EX_MARKETSTREAM_PUSH, xQBMarketStreamList_c);
    DelPtr(E_FID_QB_EX_DEAL_QUERY, xQBMarketStreamList_c);
    DelPtr(E_FID_QB_EX_DEAL_PUSH_V2, xQBMarketStreamList_c);
    DelPtr(E_FID_QB_EX_DEAL_PUSH, xQBMarketStreamList_c);
    DelPtr(E_FID_QBA_BROKER_DEAL_KLINE_DAY_CLOSE_REQ,
           xQBABrokerKlineDayCloseList_Ack);
    DelPtr(E_FID_QBA_BROKER_KLINE_DAY_CLOSE_REQ,
           xQBABrokerKlineDayCloseBoList_c);
    DelPtr(E_FID_QB_CFETS_DEAL_DAYLINE_QUERY, xQBCFETSDealDaylineAck_t);
    DelPtr(E_FID_QBA_BROKER_DEAL_KLINE_DAY_REQ, xQBABrokerDealKlineDayList_c);
    DelPtr(E_FID_QBA_YIELD_CURVE_REQ_V2, xQBAYieldCurveList_c);
    DelPtr(E_FID_QB_ISSUER_CREDIT_SPREAD_REQ, xQBIssuerCreditSpreadAck);
    DelPtr(E_FID_QB_BOND_CREDIT_SPREAD_REQ, xQBBondCreditSpreadAck);
    DelPtr(E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V2, xQBCDCPriceSingleHisAck_c);
    DelPtr(E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V3, xQBCDCPriceSingleHisAck_c);
    DelPtr(E_FID_QB_BEST_PRICE_PUSH_V2, xQBBestPriceListAck_c);
    DelPtr(E_FID_QB_CFETS_MARKETMAKER_QUOTE_QUERY, xQBBestPriceListAck_c);
    DelPtr(E_FID_QB_CFETS_MARKETMAKER_QUOTE_PUSH, xQBBestPriceListAck_c);
    DelPtr(E_FID_QB_CFETS_XBOND_QUOTE_QUERY, xQBBestPriceListAck_c);
    DelPtr(E_FID_QB_CFETS_XBOND_QUOTE_PUSH, xQBBestPriceListAck_c);
    DelPtr(E_FID_QB_BESTPRICE_SYNTHETICAL_REQ, xQBBestPriceSyntheticalAck_c);
    DelPtr(E_FID_QB_BESTPRICE_SYNTHETICAL_PUSH, xQBBestPriceSyntheticalAck_c);
    DelPtr(E_FID_QB_BESTPRICE_SYNTHETICAL_PUSH_CANCEL,
           xQBBestPriceSyntheticalAck_c);
    DelPtr(E_FID_CSI_PRICE_ALL_REQ_V2, xCSIList_c);
    DelPtr(E_FID_QB_BOND_LIQUIDITY_FULL_REQ_V2, xQBBondLiquidityFullAck_c);
    DelPtr(E_FID_QB_ISSUER_LIQUIDITY_FULL_REQ_V2, xQBIssuerLiquidityFullAck_c);
    DelPtr(E_FID_QB_HIGT_YIELD_BOND_QRY, xQBHighYieldBondListAck_c);
    DelPtr(E_FID_QB_THIRD_PARTY_GUARANTEE_QRY, xQBThirdPartyGuaranteeListAck_c);
    DelPtr(E_FID_QB_SECTOR_BOND_REQ, SectorBondAck);
    DelPtr(E_FID_MARKETMAKE_TARGET_BOND_REQ, xQBMarketMakeTargetAck_c);
    DelPtr(E_FID_QB_BOND_SS_INFO_NEW, xQBBondSSInfoNewListAck_c);
    DelPtr(E_FID_QB_BOND_SS_ISSUER_INFO_NEW, xBondIssuerInfo_c);
    DelPtr(E_FID_QB_EX_BEST_QUOTE_PUSH, xQBBestPriceListAck_c);
    DelPtr(E_FID_QB_EX_BEST_QUOTE_QUERY, xQBBestPriceListAck_c);
    DelPtr(E_FID_QB_EX_QUOTE_QUERY, xQBExQuoteList_c);
    DelPtr(E_FID_QB_EX_QUOTE_PUSH_V2, xQBExQuoteList_c);
    DelPtr(E_FID_QB_SHFI_SINGLE_QUOTE_PUSH, xQBSHFIQuoteList_c);
    DelPtr(E_FID_QB_SHFI_SINGLE_QUOTE_REQ, xQBSHFIQuoteList_c);
    DelPtr(E_FID_QB_COMPANY_SORT_REQ, xQBCompanySortReq_t);
    DelPtr(E_FID_QB_MIXED_BESTQUOTE_REQ, xQBMixedBestQuoteAck_c);
    DelPtr(E_FID_QB_MIXED_BESTQTUOE_PUSH, xQBMixedBestQuoteAck_c);
    DelPtr(E_FID_QB_ABBOND_RECOMMEND_PRICE_REQ, xQBAbBondRecommendPriceAck_t);
    DelPtr(E_FID_QB_ABBOND_RECOMMEND_PRICE_PUSH, xQBAbBondRecommendPriceAck_t);
    default:
      break;
  }
  return toDel;
}
void* qbbond::ExtracFunc(int func, const ProtoMessage& msg, void* toDel) {
  if (toDel != nullptr) return delAck(func, toDel);

  switch (func) {
    case E_FID_QB_HIS_SINGLE_DEAL_REG:
    case E_FID_QB_HIS_SINGLE_DEAL_REQ: {
      xSingleBondQuotationAck_c* ptr = new xSingleBondQuotationAck_c();

      FIELDCOPY(ptr->BondKey, CParserTool::GetString(msg, "BondKey"));
      FIELDCOPY(ptr->ListedMarket, CParserTool::GetString(msg, "ListedMarket"));
      FIELDCOPY(ptr->m_Source, CParserTool::GetString(msg, "Source"));
      FIELDCOPY(ptr->m_Type, CParserTool::GetString(msg, "Type"));
      FIELDCOPY(ptr->m_Price, CParserTool::GetString(msg, "Price"));
      FIELDCOPY(ptr->m_QuoteType, CParserTool::GetString(msg, "QuoteType"));
      FIELDCOPY(ptr->m_Yield, CParserTool::GetString(msg, "Yield"));
      FIELDCOPY(ptr->m_NetPrice, CParserTool::GetString(msg, "NetPrice"));
      FIELDCOPY(ptr->m_FullPrice, CParserTool::GetString(msg, "FullPrice"));
      FIELDCOPY(ptr->m_PreClose, CParserTool::GetString(msg, "PreClose"));
      FIELDCOPY(ptr->m_Open, CParserTool::GetString(msg, "Open"));
      FIELDCOPY(ptr->m_High, CParserTool::GetString(msg, "High"));
      FIELDCOPY(ptr->m_Low, CParserTool::GetString(msg, "Low"));
      msg.GetUInt32("TransCount", ptr->m_TransCount);
      msg.GetUInt32("TKNCount", ptr->m_TKNCount);
      msg.GetUInt32("GVNCount", ptr->m_GVNCount);
      msg.GetUInt32("TRDCount", ptr->m_TRDCount);
      CParserTool::MessageGetTime(msg, "CreateTime", ptr->m_time);
      return ptr;
    } break;
    case E_FID_QB_BOND_GRADE_INSTITUTION_REQ: {
      ProtoList msgList;
      if (!msg.getList("List", msgList)) return nullptr;
      xQBBondGradeInstitutionAck* ptr = new xQBBondGradeInstitutionAck();
      xQBBondGradeInstitutionUnit unit;
      for (ProtoList::const_iterator it = msgList.begin(); it != msgList.end();
           ++it) {
        if (it->Type != qb::proto::Variant::VAR_MAP) continue;
        memset(&unit, 0, sizeof(unit));
        const ProtoMap& msgmap = *it;
        FIELDCOPY(unit.m_bondkey, CParserTool::GetString(msgmap, "bondkey"));
        FIELDCOPY(unit.m_listedmarket,
                  CParserTool::GetString(msgmap, "listedmarket"));
        FIELDCOPY(unit.m_Issuer_Rating_Current,
                  CParserTool::GetString(msgmap, "Issuer_Rating_Current"));
        FIELDCOPY(unit.m_Rating_Current,
                  CParserTool::GetString(msgmap, "Rating_Current"));
        FIELDCOPY(unit.m_Issuer_Rating_Dept,
                  CParserTool::GetString(msgmap, "Issuer_Rating_Dept"));
        FIELDCOPY(unit.m_Rating_Current_Dept,
                  CParserTool::GetString(msgmap, "Rating_Current_Dept"));
        FIELDCOPY(unit.m_Issuer_Rating_DeptEn,
                  CParserTool::GetString(msgmap, "Issuer_Rating_DeptEn"));
        FIELDCOPY(unit.m_Rating_Current_DeptEn,
                  CParserTool::GetString(msgmap, "Rating_Current_DeptEn"));
        ptr->m_List.push_back(unit);
      }
      return ptr;
    } break;
    case E_FID_QB_BOND_CDC_SPECIAL_INFO: {
      xQBBondCDCSpecialInfoListAck_c* ptr =
          new xQBBondCDCSpecialInfoListAck_c();
      ProtoList submsg_m_List;
      if (!msg.GetList("List", submsg_m_List)) return nullptr;
      for (ProtoList::const_iterator it = submsg_m_List.begin();
           it != submsg_m_List.end(); ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;
        const ProtoMap& msgmap = *it;
        xQBBondCDCSpecialInfoUnit_c InfoUnit;
        FIELDCOPY(InfoUnit.m_bond_key,
                  CParserTool::GetString(msgmap, "bond_key"));
        FIELDCOPY(InfoUnit.m_listedmarket,
                  CParserTool::GetString(msgmap, "Listed_Market"));
        FIELDCOPY(InfoUnit.m_CDCCleanPrice,
                  CParserTool::GetString(msgmap, "CDCCleanPrice"));
        FIELDCOPY(InfoUnit.m_CDCFullPrice,
                  CParserTool::GetString(msgmap, "CDCFullPrice"));
        FIELDCOPY(InfoUnit.m_CDCYield,
                  CParserTool::GetString(msgmap, "CDCYield"));
        int nDate = 0;
        msgmap.GetInt32("Date", nDate);
        if (nDate >= 0) InfoUnit.m_Date = static_cast<UINT>(nDate);
        msgmap.GetInt32("BondProperty", InfoUnit.m_BondProperty);
        ptr->m_List.push_back(InfoUnit);
      }
      return ptr;
    } break;
    case E_FID_QBA_CDC_PRICE_ALL_REQ_V3:
    case E_FID_QBA_CDC_PRICE_SPECIAL_REQ:
      return extractQBCDCPriceAllV3(msg);

    case E_FID_QB_BEST_PRICE_REQ:
      // case E_FID_QB_EX_BEST_QUOTE_PUSH:
      // case E_FID_QB_EX_BEST_QUOTE_QUERY:
      {
        ProtoRaw rawvalue;
        if (!msg.GetRaw("BondOffer", rawvalue)) return nullptr;

        if (!rawvalue.Data) return nullptr;

        // extract data
        static char sBuffer[Y_RD_SERVICE_MESSAGE_BLOCK_LEN] = {0};
        int nLenOut = 0;
        if (!rdMessage::bUnZip((char*)rawvalue.Data, rawvalue.Length, sBuffer,
                               &nLenOut))
          return nullptr;

        // 按照字典格式解析数据
        char* sFileBuffer = sBuffer;
        size_t nStartPos, record_cnt, nFieldCnt;
        nStartPos = record_cnt = nFieldCnt = 0;
        std::vector<std::string> vHeaders;
        // parse headers
        std::string str;
#ifdef _MSC_VER
        memcpy_s(&nStartPos, sizeof(unsigned int), sFileBuffer + 4, 4);
        memcpy_s(&record_cnt, sizeof(unsigned int), sFileBuffer + 8, 4);
        memcpy_s(&nFieldCnt, sizeof(unsigned int), sFileBuffer + 12, 2);
#else
        memcpy(&nStartPos, sFileBuffer + 4, 4);
        memcpy(&record_cnt, sFileBuffer + 8, 4);
        memcpy(&nFieldCnt, sFileBuffer + 12, 2);
#endif
        sFileBuffer += 14;
        vHeaders.reserve(nFieldCnt);
        for (int i = 0; i != nFieldCnt; ++i) {
          str = sFileBuffer;
          sFileBuffer = sFileBuffer + str.length() + 2;
          vHeaders.emplace_back(str);
        }
        sFileBuffer = sFileBuffer + 8;

        xQBBestPriceListAck_c* ptr = new xQBBestPriceListAck_c();
        xQBBestPriceUnit_c unit;

        bool verbos = CParserTool::IsVerbosLogEnable();
        std::string sUTF8, sGBK;
        qb::base::CConvertFast convert;
        //	BondKey | CleanPrice | Yield | Date
        for (size_t i = 0; i != record_cnt; ++i) {
          memset(&unit, 0, sizeof(xQBBestPriceUnit_c));
          for (size_t cnt = 0; cnt != vHeaders.size(); ++cnt) {
            ++sFileBuffer;
            IFHEAD("id") { GETITEM_STRING(m_id); }
            else IFHEAD("cid") {
              GETITEM_STRING(m_company_id);
            }  // fieldstr id ;
            else IFHEAD("cn") {
              GETITEM_STRING_NULL();
            }  // fieldstr cn ;
            else IFHEAD("lm") {
              GETITEM_STRING(m_listedmarket);
            }  // fieldstr lm ;
            else IFHEAD("bk") {
              GETITEM_STRING(m_bondkey);
            }  // fieldstr bk;
            else IFHEAD("gc") {
              GETITEM_STRING_NULL();
            }  // fieldstr gc;
            else IFHEAD("gsn") {
              GETITEM_STRING_NULL();
            }  // fieldstr gsn;
            else IFHEAD("pri") {
              GETITEM_STRING(m_price);
            }  // fieldstr pri;
            else IFHEAD("qt") {
              GETITEM_STRING(m_quotetype);
            }  // fieldstr qt;
            else IFHEAD("yd") {
              GETITEM_STRING(m_yield);
            }  // fieldstr yd;
            else IFHEAD("np") {
              GETITEM_STRING(m_clean_price);
            }  // fieldstr np;
            else IFHEAD("fp") {
              GETITEM_STRING(m_full_price);
            }  // fieldstr fp;
            else IFHEAD("vol") {
              GETITEM_STRING(m_volume);
            }  // fieldstr vol;
            else IFHEAD("ds") {
              GETITEM_STRING(m_bp_status);
            }  // fieldstr ds;
            else IFHEAD("fbad") {
              GETITEM_STRING(m_flag_bad);
            }  // fieldstr fbad;
            else IFHEAD("fbar") {
              GETITEM_STRING(m_flag_bargain);
            }  // fieldstr fbar;
            else IFHEAD("fr") {
              GETITEM_STRING(m_flag_relation);
            }  // fieldstr fr;
            else IFHEAD("fv") {
              GETITEM_STRING(m_flag_vip);
            }  // fieldstr fv;
            else IFHEAD("sts") {
              GETITEM_STRING(m_status);
            }  // fieldstr sts;
            else IFHEAD("reb") {
              GETITEM_STRING(m_rebate);
            }  // fieldstr reb;
            else IFHEAD("pdesc") {
              GETITEM_STRING_UTF8(m_price_description);
            }  // fieldstr pdesc;
            else IFHEAD("intp") {
              GETITEM_STRING_UTF8(m_interpret);
            }  // fieldstr intp;
            else IFHEAD("sym") {
              GETITEM_STRING(m_symbol);
            }  // fieldstr sym;
            else IFHEAD("ps") {
              GETITEM_STRING(m_price_status);
            }  // fieldstr ps;
            else IFHEAD("desc") {
              GETITEM_STRING_UTF8(m_desc_useless);
            }  // fieldstr desc;
            else IFHEAD("rp") {
              GETITEM_STRING(m_return_point);
            }  // fieldstr rp;
            else IFHEAD("ldp") {
              GETITEM_STRING(m_tradePrice);
            }  // fieldstr ldp;
            else IFHEAD("ldnp") {
              GETITEM_STRING(m_trade_clear_Price);
            }  // fieldstr ldnp;
            // else IFHEAD("bklm"){ GETITEM_STRING(m_trade_clear_Price); }
            // //fieldstr bklm;
            else IFHEAD("fcn") {
              GETITEM_STRING_UTF8(m_fin_company_name);
            }  // fieldstr fcn;
            else IFHEAD("exec") {
              GETITEM_STRING(m_exercise);
            }  // fieldstr exec;
            else IFHEAD("ct") {
              GETITEM_BUFFER(int, m_create_time);
            }  // fieldstr ct;
            else IFHEAD("mt") {
              GETITEM_BUFFER(int, m_modify_time);
            }  // fieldstr mt;
            // else IFHEAD("ot"){ GETITEM_BUFFER(time_t, m_modify_time); }
            // fieldi32 ot;
            else IFHEAD("ver") {
              GETITEM_BUFFER(int, m_version);
            }  // fieldi32 ver;

            ELSESKIP
          }
          sFileBuffer += 8;  // jump to next record;
          ptr->m_List.push_back(unit);
        }

        ProtoMap extrmsgmap;
        if (msg.GetMap("IMQ_EXTRAINFO", extrmsgmap)) {
          ProtoList extrmsglist;
          if (extrmsgmap.getList("Version_List", extrmsglist)) {
            xQBBestPriceVersionUnit_c version_unit;
            for (ProtoList::const_iterator it = extrmsglist.begin();
                 it != extrmsglist.end(); ++it) {
              if (it->Type != qb::proto::Variant::VAR_MAP) continue;

              memset(&version_unit, 0, sizeof(xQBBestPriceVersionUnit_c));
              const ProtoMap& msgmap = *it;

              FIELDCOPY(version_unit.m_company_id,
                        CParserTool::GetString(msgmap, "BF_CompanyID"));
              msgmap.GetInt32("BF_Version", version_unit.m_version);

              ptr->m_extList.push_back(version_unit);
            }
          }
        }

        return ptr;
      }
      break;
    case E_FID_QB_BEST_PRICE_PUSH_V2: {
      const char* bk = "1";
      const char* cid = "2";
      // const char* cn = "3";
      const char* ct = "3";
      const char* desc = "4";
      const char* ds = "5";
      const char* fbad = "6";
      const char* fbar = "7";
      const char* fcn = "8";
      const char* fp = "9";
      const char* fr = "10";
      const char* fv = "11";
      // const char* gc = "13";
      // const char* gsn = "14";
      const char* id = "12";
      const char* ldnp = "13";
      const char* ldp = "14";
      const char* lm = "15";
      const char* mt = "16";
      const char* np = "17";
      const char* pdesc = "18";
      const char* pri = "19";
      const char* ps = "20";
      const char* qt = "21";
      const char* reb = "22";
      const char* rp = "23";
      const char* sts = "24";
      const char* sym = "25";
      const char* ver = "26";
      const char* vol = "27";
      const char* yd = "28";
      const char* intp = "29";
      const char* exec = "30";
      // OutputDebugString(_T("ExtractQBBestPriceList begin\n"));

      qb::base::msg::Raw raw;
      if (!msg.GetRaw("list", raw)) return nullptr;

      qb::proto::VariantTableDecoder msglist;
      if (!msglist.decode((const char*)raw.Data, raw.Length)) return nullptr;

      xQBBestPriceListAck_c* ptr = new xQBBestPriceListAck_c();
      FIELDCOPY(ptr->m_BusinessCode,
                CParserTool::GetString(msg, "BusinessCode"));

      xQBBestPriceUnit_c bestprice_unit;
      std::string tmp;
      bool verbos = CParserTool::IsVerbosLogEnable();
      for (auto it = msglist.begin(); it != msglist.end(); ++it) {
        memset(&bestprice_unit, 0, sizeof(xQBBestPriceUnit_c));
        tmp.clear();
        const qb::proto::VariantRecord* msgmap = *it;

        // 调整字段的顺序,使得按照名称递增排序来访问,可以达到最高性能
        // 做法:查找	.*\"(\w+)\".*
        //		替换	\1\t\0
        //		选中然后排序
        FIELDCOPY(bestprice_unit.m_bondkey, CParserTool::GetString(msgmap, bk));
        FIELDCOPY(bestprice_unit.m_company_id,
                  CParserTool::GetString(msgmap, cid));
        // FIELDCOPY(bestprice_unit.m_company_name,
        // CParserTool::GetString(msgmap, cn));
        CParserTool::MessageGetTime(msgmap, ct, bestprice_unit.m_create_time);
        FIELDCOPY(bestprice_unit.m_desc_useless,
                  CParserTool::GetString(msgmap, desc));
        FIELDCOPY(bestprice_unit.m_bp_status,
                  CParserTool::GetString(msgmap, ds));
        FIELDCOPY(bestprice_unit.m_flag_bad,
                  CParserTool::GetString(msgmap, fbad));
        FIELDCOPY(bestprice_unit.m_flag_bargain,
                  CParserTool::GetString(msgmap, fbar));
        FIELDCOPY(bestprice_unit.m_fin_company_name,
                  CParserTool::GetString(msgmap, fcn));
        FIELDCOPY(bestprice_unit.m_full_price,
                  CParserTool::GetString(msgmap, fp));
        FIELDCOPY(bestprice_unit.m_flag_relation,
                  CParserTool::GetString(msgmap, fr));
        FIELDCOPY(bestprice_unit.m_flag_vip,
                  CParserTool::GetString(msgmap, fv));
        // FIELDCOPY(bestprice_unit.m_bond_code, CParserTool::GetString(msgmap,
        // gc)); FIELDCOPY(bestprice_unit.m_bond_shorname,
        // CParserTool::GetString(msgmap, gsn));
        FIELDCOPY(bestprice_unit.m_id, CParserTool::GetString(msgmap, id));
        FIELDCOPY(bestprice_unit.m_trade_clear_Price,
                  CParserTool::GetString(msgmap, ldnp));
        FIELDCOPY(bestprice_unit.m_tradePrice,
                  CParserTool::GetString(msgmap, ldp));
        FIELDCOPY(bestprice_unit.m_listedmarket,
                  CParserTool::GetString(msgmap, lm));
        CParserTool::MessageGetTime(msgmap, mt, bestprice_unit.m_modify_time);
        FIELDCOPY(bestprice_unit.m_clean_price,
                  CParserTool::GetString(msgmap, np));
        FIELDCOPY(bestprice_unit.m_price_description,
                  CParserTool::GetString(msgmap, pdesc));
        FIELDCOPY(bestprice_unit.m_price, CParserTool::GetString(msgmap, pri));
        FIELDCOPY(bestprice_unit.m_price_status,
                  CParserTool::GetString(msgmap, ps));
        FIELDCOPY(bestprice_unit.m_quotetype,
                  CParserTool::GetString(msgmap, qt));
        FIELDCOPY(bestprice_unit.m_rebate, CParserTool::GetString(msgmap, reb));
        FIELDCOPY(bestprice_unit.m_return_point,
                  CParserTool::GetString(msgmap, rp));
        FIELDCOPY(bestprice_unit.m_status, CParserTool::GetString(msgmap, sts));
        FIELDCOPY(bestprice_unit.m_symbol, CParserTool::GetString(msgmap, sym));
        msgmap->getInt32(ver, bestprice_unit.m_version);
        FIELDCOPY(bestprice_unit.m_volume, CParserTool::GetString(msgmap, vol));
        FIELDCOPY(bestprice_unit.m_yield, CParserTool::GetString(msgmap, yd));
        FIELDCOPY(bestprice_unit.m_interpret,
                  CParserTool::GetString(msgmap, intp));
        FIELDCOPY(bestprice_unit.m_exercise,
                  CParserTool::GetString(msgmap, exec));

        ptr->m_List.push_back(bestprice_unit);

        {
          // 延迟日志
          static time_t lastWaring = 0;
          bool bDelay = false;
          time_t tNow = ServerTimeMgr::instance().serverTime();
          if (func == E_FID_QB_BEST_PRICE_PUSH_V2)  // 只看最优报价
          {
            time_t tQuote = qMax(bestprice_unit.m_create_time,
                                 bestprice_unit.m_modify_time);
            if (tNow - tQuote >= 3 &&
                tNow - lastWaring > 60)  // 延迟3秒，每分钟打印
            {
              lastWaring = tNow;
              bDelay = true;
            }
          }

          if (bDelay) {
            int bondIndex = CBondContainer::instance().GetBondIndex(
                bestprice_unit.m_bondkey, bestprice_unit.m_listedmarket);
            const CBondInfo& bi =
                CBondContainer::instance().ElementAtR(bondIndex);
            qb::base::CTime TNow(tNow);
            qb::base::CTime T0(bestprice_unit.m_create_time);
            qb::base::CTime T1(bestprice_unit.m_modify_time);

            log_warning(
                "[{%s}][{%d}][BestPrice]BOND=[{%s}.{%s}],\
								CompanyID={%s},Symbol(1-bid)={%s},Price={%s},Vol={%s},Version={%d},\
								deal_status={%s},price_status={%s},\
								CreateTime={%d}-{%d}-{%d} {%d}:{%d}:{%d},\
								ModifyTime={%d}-{%d}-{%d} {%d}:{%d}:{%d}",
                (bDelay ? "Delay" : "verbos"), func, bestprice_unit.m_bondkey,
                bestprice_unit.m_listedmarket, bestprice_unit.m_company_id,
                bestprice_unit.m_symbol, bestprice_unit.m_price,
                bestprice_unit.m_volume, bestprice_unit.m_version,
                bestprice_unit.m_bp_status, bestprice_unit.m_price_status,
                T0.GetYear(), T0.GetMonth(), T0.GetDay(), T0.GetHour(),
                T0.GetMinute(), T0.GetSecond(), T1.GetYear(), T1.GetMonth(),
                T1.GetDay(), T1.GetHour(), T1.GetMinute(), T1.GetSecond());
          }
        }
      }

      ProtoMap extrmsgmap;
      if (msg.GetMap("IMQ_EXTRAINFO", extrmsgmap)) {
        ProtoList extrmsglist;
        if (extrmsgmap.getList("Version_List", extrmsglist)) {
          xQBBestPriceVersionUnit_c version_unit;
          for (ProtoList::const_iterator it = extrmsglist.begin();
               it != extrmsglist.end(); ++it) {
            if (it->Type != ProtoValue::VAR_MAP) continue;

            memset(&version_unit, 0, sizeof(xQBBestPriceVersionUnit_c));
            const ProtoMap& msgmap = *it;

            FIELDCOPY(version_unit.m_company_id,
                      CParserTool::GetString(msgmap, "BF_CompanyID"));
            msgmap.GetInt32("BF_Version", version_unit.m_version);

            ptr->m_extList.push_back(version_unit);
          }
        }
      }
      return ptr;
    } break;
    case E_FID_QB_MARKET_STREAM_REQ:
    case E_FID_QB_EX_MARKETSTREAM_QUERY_NEW:
    case E_FID_QB_CFETS_MARKET_STREAM_REQ:
    case E_FID_QB_CFETS_MARKET_STREAM_REQ_NEW:
    case E_FID_QB_MARKET_STREAM_DEAL_REQ:
    case E_FID_QB_MARKET_STREAM_DEAL_PUSH:
    case E_FID_QB_MARKET_STREAM_BY_GROUP_QRY:
    case E_FID_QB_CFETS_DEAL_PUSH:
    case E_FID_QB_CFETS_MARKET_STREAM_DEAL_REQ:
    case E_FID_QB_EX_MARKETSTREAM_PUSH:
    case E_FID_QB_EX_DEAL_QUERY:
    case E_FID_QB_EX_DEAL_PUSH_V2:
    case E_FID_QB_EX_DEAL_PUSH:
    case E_FID_QB_MARKET_STREAM_HIS_QRY3:
    case E_FID_QB_MARKET_STREAM_HIS_DEAL_QRY2:
    case E_FID_QB_TF_MARKET_STREAM_DEAL_REQ:
    case E_FID_QB_CFETS_DEAL_TICK_ALL_REQ:
    case E_FID_QB_CFETS_DEAL_TICK_ALL_PUSH:
    case E_FID_QB_CFETS_DEAL_MARKETMAKER_ALL_REQ:
    case E_FID_QB_CFETS_DEAL_MARKETMAKER_ALL_PUSH: {
      ProtoList msglist;
      if (!msg.getList("IMQ_OUTCOME", msglist)) return nullptr;

      xQBMarketStreamList_c* ptr = new xQBMarketStreamList_c();
      FIELDCOPY(ptr->m_BusinessCode,
                CParserTool::GetString(msg, "BusinessCode"));

      xQBMarketStreamUnit_c marketstream_unit;
      ProtoMap submsg;
      bool verbos = CParserTool::IsVerbosLogEnable();
      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(&marketstream_unit, 0, sizeof(xQBMarketStreamUnit_c));
        const ProtoMap& msgmap = *it;

        FIELDCOPY(marketstream_unit.m_company_id,
                  CParserTool::GetString(msgmap, "MS_COMPANY_ID"));
        CParserTool::MessageGetTime(msgmap, "MS_CREATE_TIME",
                                    marketstream_unit.m_create_time);
        FIELDCOPY(marketstream_unit.m_dept,
                  CParserTool::GetString(msgmap, "MS_DEPT"));
        CParserTool::MessageGetTime(msgmap, "MS_MODIFY_TIME",
                                    marketstream_unit.m_modify_time);
        FIELDCOPY(marketstream_unit.m_operate,
                  CParserTool::GetString(msgmap, "MS_OPERATE"));
        FIELDCOPY(marketstream_unit.m_type,
                  CParserTool::GetString(msgmap, "MS_TYPE"));
        msgmap.getInt32("MS_Version", marketstream_unit.m_indexID);

        if (msgmap.GetMap("MS_BODY", submsg)) {
          if (0 == strcmp("1", marketstream_unit.m_type)) {
            FIELDCOPY(marketstream_unit.m_body1.m_bid_companyname,
                      CParserTool::GetString(submsg, "MS_bidCompanyName"));
            FIELDCOPY(marketstream_unit.m_body1.m_bidExercise,
                      CParserTool::GetString(submsg, "MS_bidExercise"));
            FIELDCOPY(marketstream_unit.m_body1.m_bidflag_bargain,
                      CParserTool::GetString(submsg, "MS_bidFlagBargain"));
            FIELDCOPY(marketstream_unit.m_body1.m_bidflag_relation,
                      CParserTool::GetString(submsg, "MS_bidFlagRelation"));
            FIELDCOPY(marketstream_unit.m_body1.m_bid_cleanprice,
                      CParserTool::GetString(submsg, "MS_bidNetPrice"));
            FIELDCOPY(marketstream_unit.m_body1.m_bidOfferId,
                      CParserTool::GetString(submsg, "MS_bidOfferId"));
            FIELDCOPY(marketstream_unit.m_body1.m_bidprice,
                      CParserTool::GetString(submsg, "MS_bidPrice"));
            FIELDCOPY(marketstream_unit.m_body1.m_bid_description,
                      CParserTool::GetString(submsg, "MS_bidPriceDescription"));
            FIELDCOPY(marketstream_unit.m_body1.m_bid_interpret,
                      CParserTool::GetString(submsg, "MS_bidInterpret"));
            FIELDCOPY(marketstream_unit.m_body1.m_bidRebate,
                      CParserTool::GetString(submsg, "MS_bidRebate"));
            FIELDCOPY(marketstream_unit.m_body1.m_bidReturn_point,
                      CParserTool::GetString(submsg, "MS_bidReturnPoint"));
            FIELDCOPY(marketstream_unit.m_body1.m_bidvolume,
                      CParserTool::GetString(submsg, "MS_bidVolume"));
            FIELDCOPY(marketstream_unit.m_body1.m_bid_yield,
                      CParserTool::GetString(submsg, "MS_bidYield"));
            FIELDCOPY(marketstream_unit.m_body1.m_bondkey,
                      CParserTool::GetString(msgmap, "MS_BOND_KEY"));
            FIELDCOPY(marketstream_unit.m_body1.m_bidQuotetype,
                      CParserTool::GetString(submsg, "MS_bidQuoteType"));
            CParserTool::MessageGetTime(submsg, "MS_createTime",
                                        marketstream_unit.m_body1.m_createTime);
            FIELDCOPY(marketstream_unit.m_body1.m_listedmarket,
                      CParserTool::GetString(msgmap, "MS_LISTED_MARKET"));
            FIELDCOPY(marketstream_unit.m_body1.m_ofr_companyname,
                      CParserTool::GetString(submsg, "MS_ofrCompanyName"));
            FIELDCOPY(marketstream_unit.m_body1.m_ofrExercise,
                      CParserTool::GetString(submsg, "MS_ofrExercise"));
            FIELDCOPY(marketstream_unit.m_body1.m_ofrflag_bargain,
                      CParserTool::GetString(submsg, "MS_ofrFlagBargain"));
            FIELDCOPY(marketstream_unit.m_body1.m_ofrflag_relation,
                      CParserTool::GetString(submsg, "MS_ofrFlagRelation"));
            FIELDCOPY(marketstream_unit.m_body1.m_ofr_cleanprice,
                      CParserTool::GetString(submsg, "MS_ofrNetPrice"));
            FIELDCOPY(marketstream_unit.m_body1.m_ofrOfferId,
                      CParserTool::GetString(submsg, "MS_ofrOfferId"));
            FIELDCOPY(marketstream_unit.m_body1.m_ofrprice,
                      CParserTool::GetString(submsg, "MS_ofrPrice"));
            FIELDCOPY(marketstream_unit.m_body1.m_ofr_description,
                      CParserTool::GetString(submsg, "MS_ofrPriceDescription"));
            FIELDCOPY(marketstream_unit.m_body1.m_ofr_interpret,
                      CParserTool::GetString(submsg, "MS_ofrInterpret"));
            FIELDCOPY(marketstream_unit.m_body1.m_ofrRebate,
                      CParserTool::GetString(submsg, "MS_ofrRebate"));
            FIELDCOPY(marketstream_unit.m_body1.m_ofrReturn_point,
                      CParserTool::GetString(submsg, "MS_ofrReturnPoint"));
            FIELDCOPY(marketstream_unit.m_body1.m_ofrvolume,
                      CParserTool::GetString(submsg, "MS_ofrVolume"));
            FIELDCOPY(marketstream_unit.m_body1.m_ofr_yield,
                      CParserTool::GetString(submsg, "MS_ofrYield"));
            FIELDCOPY(marketstream_unit.m_body1.m_ofrQuotetype,
                      CParserTool::GetString(submsg, "MS_ofrQuoteType"));

            // 可转债显示净价
            int bondIndex = CBondContainer::instance().GetBondIndex(
                marketstream_unit.m_body1.m_bondkey,
                marketstream_unit.m_body1.m_listedmarket);
            const CBondInfo& bond =
                CBondContainer::instance().ElementAtR(bondIndex);
            if (bond.IsTransBond() &&
                strcmp(marketstream_unit.m_company_id, "e") == 0) {
              if (marketstream_unit.m_body1.m_bid_cleanprice[0] != '\0')
                FIELDCOPY(marketstream_unit.m_body1.m_bidprice,
                          marketstream_unit.m_body1.m_bid_cleanprice);
              if (marketstream_unit.m_body1.m_ofr_cleanprice[0] != '\0')
                FIELDCOPY(marketstream_unit.m_body1.m_ofrprice,
                          marketstream_unit.m_body1.m_ofr_cleanprice);
            }
          } else if (0 == strcmp("2", marketstream_unit.m_type)) {
            FIELDCOPY(marketstream_unit.m_body2.m_bondkey,
                      CParserTool::GetString(msgmap, "MS_BOND_KEY"));
            CParserTool::MessageGetTime(submsg, "MS_createTime",
                                        marketstream_unit.m_body2.m_createTime);
            FIELDCOPY(marketstream_unit.m_body2.m_dealStatus,
                      CParserTool::GetString(submsg, "MS_dealStatus"));
            FIELDCOPY(marketstream_unit.m_body2.m_exercise,
                      CParserTool::GetString(submsg, "MS_exercise"));
            FIELDCOPY(marketstream_unit.m_body2.m_settlementType,
                      CParserTool::GetString(submsg, "MS_settlementType"));
            FIELDCOPY(
                marketstream_unit.m_body2.m_settlementDescription,
                CParserTool::GetString(submsg, "MS_settlementDescription"));
            FIELDCOPY(marketstream_unit.m_body2.m_fullPrice,
                      CParserTool::GetString(submsg, "MS_fullPrice"));
            FIELDCOPY(marketstream_unit.m_body2.m_id,
                      CParserTool::GetString(submsg, "MS_id"));
            FIELDCOPY(marketstream_unit.m_body2.m_listedmarket,
                      CParserTool::GetString(msgmap, "MS_LISTED_MARKET"));
            FIELDCOPY(marketstream_unit.m_body2.m_cleanPrice,
                      CParserTool::GetString(submsg, "MS_netPrice"));
            FIELDCOPY(marketstream_unit.m_body2.m_price,
                      CParserTool::GetString(submsg, "MS_price"));
            FIELDCOPY(marketstream_unit.m_body2.m_rebate,
                      CParserTool::GetString(submsg, "MS_rebate"));
            FIELDCOPY(marketstream_unit.m_body2.m_return_point,
                      CParserTool::GetString(submsg, "MS_return_point"));
            FIELDCOPY(marketstream_unit.m_body2.m_volume,
                      CParserTool::GetString(submsg, "MS_volume"));
            FIELDCOPY(marketstream_unit.m_body2.m_yield,
                      CParserTool::GetString(submsg, "MS_yield"));
            FIELDCOPY(marketstream_unit.m_body2.m_quotetype,
                      CParserTool::GetString(submsg, "MS_quoteType"));
            FIELDCOPY(marketstream_unit.m_body2.m_tradeMode,
                      CParserTool::GetString(submsg, "MS_tradeMode"));

            // 可转债显示净价
            int bondIndex = CBondContainer::instance().GetBondIndex(
                marketstream_unit.m_body2.m_bondkey,
                marketstream_unit.m_body2.m_listedmarket);
            const CBondInfo& bond =
                CBondContainer::instance().ElementAtR(bondIndex);
            if (bond.IsTransBond() &&
                strcmp(marketstream_unit.m_company_id, "e") == 0) {
              if (marketstream_unit.m_body2.m_cleanPrice[0] != '\0')
                FIELDCOPY(marketstream_unit.m_body2.m_price,
                          marketstream_unit.m_body2.m_cleanPrice);
            }

            // #ifdef SSBONDNET_LOG
            {  // 延迟日志
              bool bDelay = false;
              static time_t lastWarning2 = 0;
              time_t tNow = ServerTimeMgr::instance().serverTime();
              if (func == E_FID_QB_MARKET_STREAM_DEAL_PUSH)  // 只看成交
              {
                time_t tDeal = marketstream_unit.m_modify_time;
                if (tNow - tDeal >= 3 &&
                    tNow - lastWarning2 > 60)  // 延迟3秒，每分钟打印
                {
                  lastWarning2 = tNow;
                  bDelay = true;
                }
              }
              if (bDelay) {
                qb::base::CTime T(marketstream_unit.m_modify_time);
                log_warning(
                    "[%s][{%d}][BondDeal]--BOND=[{%s}.{%s}],BrokerID={%s},"
                    "Price={%s},Status={%s},MS_id={%s},Version={%d},ModifyTime="
                    "{%d}-{%d}-{%d} {%d}:{%d}:{%d}",
                    "Delay", func, marketstream_unit.m_body2.m_bondkey,
                    marketstream_unit.m_body2.m_listedmarket,
                    marketstream_unit.m_company_id,
                    marketstream_unit.m_body2.m_price,
                    marketstream_unit.m_body2.m_dealStatus,
                    marketstream_unit.m_body2.m_id, marketstream_unit.m_indexID,
                    T.GetYear(), T.GetMonth(), T.GetDay(), T.GetHour(),
                    T.GetMinute(), T.GetSecond());
              }
            }
          }
        }

        ptr->m_List.push_back(marketstream_unit);
      }

      return ptr;
    } break;
    case E_FID_QBA_BROKER_DEAL_KLINE_DAY_CLOSE_REQ: {
      ProtoList msglist;
      if (!msg.getList("List", msglist)) return nullptr;

      xQBABrokerKlineDayCloseList_Ack* ptr =
          new xQBABrokerKlineDayCloseList_Ack();
      FIELDCOPY(ptr->m_markettype, CParserTool::GetString(msg, "markettype"));
      xQBABrokerKlineDayCloseUnit_c dealklday_unit;
      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(&dealklday_unit, 0, sizeof(xQBABrokerKlineDayCloseUnit_c));
        const ProtoMap& msgmap = *it;

        FIELDCOPY(dealklday_unit.m_bond_key,
                  CParserTool::GetString(msgmap, "bond_key"));
        FIELDCOPY(dealklday_unit.m_listed_market,
                  CParserTool::GetString(msgmap, "listed_market"));
        msgmap.GetFloat("Yield", dealklday_unit.m_Yield);
        msgmap.GetFloat("AverageClean", dealklday_unit.m_AverageClean);
        msgmap.GetFloat("CloseClean", dealklday_unit.m_CloseClean);
        msgmap.getUint32("Date", dealklday_unit.m_Date);

        ptr->m_List.push_back(dealklday_unit);
      }
      return ptr;
    } break;
    case E_FID_QBA_BROKER_KLINE_DAY_CLOSE_REQ: {
      ProtoList msglist;
      if (!msg.getList("List", msglist)) return nullptr;

      xQBABrokerKlineDayCloseBoList_c* ptr =
          new xQBABrokerKlineDayCloseBoList_c();
      xQBABrokerKlineDayCloseBoUnit_c dealklday_unit;
      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(&dealklday_unit, 0, sizeof(xQBABrokerDealKlineDayUnit_c));
        const ProtoMap& msgmap = *it;

        FIELDCOPY(dealklday_unit.m_bond_key,
                  CParserTool::GetString(msgmap, "bond_key"));
        msgmap.GetFloat("BidCloseYield", dealklday_unit.m_BidCloseYield);
        msgmap.GetFloat("OfrCloseYield", dealklday_unit.m_OfrCloseYield);
        msgmap.GetFloat("BidCloseClean", dealklday_unit.m_BidCloseClean);
        msgmap.GetFloat("OfrCloseYClean", dealklday_unit.m_OfrCloseYClean);
        msgmap.getUint32("Date", dealklday_unit.m_Date);

        ptr->m_List.push_back(dealklday_unit);
      }

      return ptr;
    } break;
    case E_FID_QB_CFETS_DEAL_DAYLINE_QUERY: {
      ProtoList msglist;
      if (!msg.getList("List", msglist)) return nullptr;

      xQBCFETSDealDaylineAck_t* ptr = new xQBCFETSDealDaylineAck_t();
      FIELDCOPY(ptr->m_bond_key, CParserTool::GetString(msg, "bond_key"));
      FIELDCOPY(ptr->m_listed_market,
                CParserTool::GetString(msg, "listed_market"));

      QBCFETSDealDaylineUnit unit;
      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(&unit, 0, sizeof(QBCFETSDealDaylineUnit));
        const ProtoMap& msgmap = *it;

        msgmap.GetFloat("Yield", unit.m_Yield);
        msgmap.GetInt32("Symbol", unit.m_Symbol);
        msgmap.getUint32("Date", unit.m_Date);

        ptr->m_List.push_back(unit);
      }
      return ptr;
    } break;
    case E_FID_QBA_BROKER_DEAL_KLINE_DAY_REQ: {
      ProtoList msglist;
      if (!msg.getList("List", msglist)) return nullptr;

      xQBABrokerDealKlineDayList_c* ptr = new xQBABrokerDealKlineDayList_c();
      xQBABrokerDealKlineDayUnit_c dealklday_unit;
      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(&dealklday_unit, 0, sizeof(xQBABrokerDealKlineDayUnit_c));
        const ProtoMap& msgmap = *it;

        FIELDCOPY(dealklday_unit.m_bond_key,
                  CParserTool::GetString(msgmap, "bond_key"));
        FIELDCOPY(dealklday_unit.m_listedmarket,
                  CParserTool::GetString(msgmap, "listed_market"));
        msgmap.GetFloat("Yield", dealklday_unit.m_Yield);
        FIELDCOPY(dealklday_unit.m_Deal_type,
                  CParserTool::GetString(msgmap, "Deal_type"));
        msgmap.getUint32("Date", dealklday_unit.m_Date);

        ptr->m_List.push_back(dealklday_unit);
      }
      return ptr;
    } break;
    case E_FID_QBA_YIELD_CURVE_REQ_V2: {
      ProtoList msglist;
      if (!msg.getList("List", msglist)) return nullptr;

      xQBAYieldCurveList_c* ptr = new xQBAYieldCurveList_c();
      ptr->m_CurveType[0] = '\0';
      ptr->m_CurveName[0] = '\0';
      ptr->m_Date = 0;

      FIELDCOPY(ptr->m_CurveType, CParserTool::GetString(msg, "CurveType"));
      FIELDCOPY(ptr->m_CurveName, CParserTool::GetString(msg, "CurveName"));
      msg.GetUInt32("Date", ptr->m_Date);

      xQBAYieldCurveUnit_c yieldcurve_unit;
      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(&yieldcurve_unit, 0, sizeof(xQBAYieldCurveUnit_c));
        const ProtoMap& msgmap = *it;

        FIELDCOPY(yieldcurve_unit.m_Period,
                  CParserTool::GetString(msgmap, "Period"));
        msgmap.GetFloat("Yield", yieldcurve_unit.m_Yield);

        ptr->m_List.push_back(yieldcurve_unit);
      }
      return ptr;
    } break;
    case E_FID_QB_ISSUER_CREDIT_SPREAD_REQ: {
      return extractQBIssuerCreditSpreadAck(msg);
    } break;
    case E_FID_QB_BOND_CREDIT_SPREAD_REQ: {
      return extractQBBondCreditSpreadAck(msg);
    } break;
    case E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V2:
    case E_FID_QB_CDC_PRICE_SINGLE_HIS_REQ_V3: {
      ProtoList msglist;
      if (!msg.getList("PriceList", msglist)) return nullptr;

      xQBCDCPriceSingleHisAck_c* ptr = new xQBCDCPriceSingleHisAck_c();
      FIELDCOPY(ptr->m_bond_key, CParserTool::GetString(msg, "bond_key"));
      FIELDCOPY(ptr->m_Listed_Market,
                CParserTool::GetString(msg, "Listed_Market"));

      xQBCDCPriceSingleHis_c cdcpricesingle_unit;
      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(&cdcpricesingle_unit, 0, sizeof(xQBCDCPriceSingleHis_c));
        const ProtoMap& msgmap = *it;

        CParserTool::MessageGetTime(msgmap, "Date", cdcpricesingle_unit.m_Date);
        msgmap.GetFloat("CleanPrice", cdcpricesingle_unit.m_CleanPrice);
        msgmap.GetFloat("FullPrice", cdcpricesingle_unit.m_FullPRice);
        msgmap.GetFloat("Yield", cdcpricesingle_unit.m_Yield);
        msgmap.GetFloat("Modified_Duration",
                        cdcpricesingle_unit.m_Modified_Duration);
        msgmap.GetFloat("Convexity", cdcpricesingle_unit.m_Convexity);
        msgmap.GetFloat("Basis_Point_Value",
                        cdcpricesingle_unit.m_Basis_Point_Value);
        msgmap.GetFloat("Spread_Duration",
                        cdcpricesingle_unit.m_Spread_Duration);
        msgmap.GetFloat("Spread_Convexity",
                        cdcpricesingle_unit.m_Spread_Convexity);
        FIELDCOPY(cdcpricesingle_unit.m_Credibility,
                  CParserTool::GetString(msgmap, "Credibility"));
        msgmap.GetFloat("Market_Dirty_Price",
                        cdcpricesingle_unit.m_Market_Dirty_Price);
        msgmap.GetFloat("Market_Clean_Price",
                        cdcpricesingle_unit.m_Market_Clean_Price);
        msgmap.GetFloat("Market_Yield", cdcpricesingle_unit.m_Market_Yield);
        msgmap.GetFloat("Market_Modified_Duration",
                        cdcpricesingle_unit.m_Market_Modified_Duration);
        msgmap.GetFloat("Market_Convexity",
                        cdcpricesingle_unit.m_Market_Convexity);
        msgmap.GetFloat("Market_Basis_Point_Value",
                        cdcpricesingle_unit.m_Market_Basis_Point_Value);
        msgmap.GetFloat("Market_Spread_Duration",
                        cdcpricesingle_unit.m_Market_Spread_Duration);
        msgmap.GetFloat("Market_Spread_Convexity",
                        cdcpricesingle_unit.m_Market_Spread_Convexity);
        FIELDCOPY(cdcpricesingle_unit.m_cdcExercise,
                  CParserTool::GetString(msgmap, "cdcExercise"));

        ptr->m_PriceList.push_back(cdcpricesingle_unit);
      }

      return ptr;
    } break;
    case E_FID_QB_CFETS_BEST_QUOTE_QUERY:
    case E_FID_QB_CFETS_MARKETMAKER_QUOTE_QUERY:
    case E_FID_QB_CFETS_MARKETMAKER_QUOTE_PUSH:
    case E_FID_QB_CFETS_XBOND_QUOTE_QUERY:
    case E_FID_QB_CFETS_XBOND_QUOTE_PUSH:
    case E_FID_QB_EX_BEST_QUOTE_PUSH:
    case E_FID_QB_EX_BEST_QUOTE_QUERY:
      return extractQBBestPriceList(msg);
      break;
    case E_FID_QB_EX_QUOTE_QUERY:
      return extractQBExQuoteList(msg);
      break;
    case E_FID_QB_EX_QUOTE_PUSH_V2:
      return extractQBExQuoteListSimplify(msg);
      break;
    case E_FID_QB_SHFI_SINGLE_QUOTE_REQ:
    case E_FID_QB_SHFI_SINGLE_QUOTE_PUSH:
      return extractQBSHFIQuoteList(msg);
      break;
    case E_FID_QB_BESTPRICE_SYNTHETICAL_REQ:
    case E_FID_QB_BESTPRICE_SYNTHETICAL_PUSH:
      return extractBestPriceSynthetical(msg);
      break;
    case E_FID_CSI_PRICE_ALL_REQ_V2:
      return extractCsiV2(msg);
    case E_FID_QB_BOND_LIQUIDITY_FULL_REQ_V2:
      return extractQBBondLiquidityFullAck_TableCodec(msg);
    case E_FID_QB_ISSUER_LIQUIDITY_FULL_REQ_V2:
      return extractQBIssuerLiquidityFullAck_TableCodec(msg);
    case E_FID_QB_HIGT_YIELD_BOND_QRY:
      return extractQBHighYieldBondListAck(msg);
    case E_FID_QB_THIRD_PARTY_GUARANTEE_QRY:
      return extractQBThirdPartyGuaranteeListAck(msg);
    case E_FID_QB_SECTOR_BOND_REQ:
      return extractSectorBondAck(msg);
    case E_FID_MARKETMAKE_TARGET_BOND_REQ:
      return extractMarketMakeTarget(msg);
    case E_FID_QB_BOND_SS_INFO_NEW:
      return extractQBBondSSInfoNewList(msg);
    case E_FID_QB_BOND_SS_ISSUER_INFO_NEW:
      return extractBondIssuerInfo(msg);
    case E_FID_QB_MIXED_BESTQUOTE_REQ:
    case E_FID_QB_MIXED_BESTQTUOE_PUSH:
      return extractQBMixedBestquoteCodec(msg);
    case E_FID_QB_ABBOND_RECOMMEND_PRICE_REQ:
      return extractQBABBondRecommendPriceAck(msg);
    default:
      break;
  }

  return nullptr;
}

void qbbond::makeHisSingleDealReq(qb::proto::Message& msg,
                                  qb::SSRequestMsg* req) {
  xSingleBondQuotationReq_c* pdata =
      (xSingleBondQuotationReq_c*)req->m_pRequest;
  qb::proto::VariantMap submsg;
  submsg.setString("BondKey", pdata->BondKey);
  submsg.SetString("ListedMarket", pdata->ListedMarket);
  submsg.SetString("Source", pdata->m_Source);
  msg.SetMap("xSingleBondQuotationReq", submsg);
}

void qbbond::makeMarketStreamReq(qb::proto::Message& msg,
                                 qb::SSRequestMsg* req) {
  SSUserAccountManager& uam = SSUserAccountManager::instance();
  qb::proto::Message::List company_id_list;
  char bufferid[32] = {0};

  bool bNCD = false;
  QBMarketStreamReq_t* pdata = (QBMarketStreamReq_t*)req->m_pRequest;
  {
    CBondContainer& bc = CBondContainer::instance();
    CBondContainer::ScopedLock l(bc);
    int nBondIndex = bc.GetBondIndex(pdata->m_bondkey, pdata->m_listedmarket);
    bNCD = bc.ElementAtR(nBondIndex).IsBondNCD();
  }

  msg.setString("UserName",
                uam.GetUserInfo().m_UserAccount);  // 用于查问题时区分用户请求
  msg.setString("IMQ_RequestType", "MARKETSTREAM");
  for (std::list<xQBTradeCmpyInfo_c>::const_iterator it = pdata->m_List.begin();
       it != pdata->m_List.end(); ++it) {
    qb::proto::VariantMap msglist;
    int nID = 0;
    if (it->m_Id > 0) {
      bufferid[0] = '\0';
      sprintf(bufferid, "%d", it->m_Id);
      msglist.setString("IMQ_CompanyID", bufferid);
      nID = it->m_Id;
    } else {
      msglist.setString("IMQ_CompanyID", it->m_BrokerID);
      nID = atoi(it->m_BrokerID);
    }
    company_id_list.push_back(msglist);
  }
  if (company_id_list.size() <= 0)
    return;  // 无权限，不请求，add by lance 20170725
  msg.setList("IMQ_CompanyID", company_id_list);
  msg.setInt32("IMQ_VersionFrom", pdata->m_IndexFrom);
  msg.setInt32("IMQ_VersionTo", pdata->m_IndexTo);
  msg.setString("IMQ_BondKey", pdata->m_bondkey);
  msg.setString("IMQ_ListedMarket", pdata->m_listedmarket);
  msg.setString("IMQ_traderID", pdata->m_traderId);
  qb::proto::Message::List trade_type_list;
  for (std::list<xQBTradeType_c>::const_iterator it =
           pdata->m_TradeTypeList.begin();
       it != pdata->m_TradeTypeList.end(); ++it) {
    qb::proto::VariantMap msgTrade;
    msgTrade.setString("IMQ_Type", it->TradeType);
    trade_type_list.push_back(msgTrade);
  }
  msg.setList("IMQ_Type", trade_type_list);
}

void qbbond::makeMarketStreamDealReq(qb::proto::Message& msg,
                                     qb::SSRequestMsg* req) {
  SSUserAccountManager& uam = SSUserAccountManager::instance();
  qb::proto::Message::List company_id_list;
  char bufferid[32] = {0};
  QBMarketStreamReq_t* pdata = (QBMarketStreamReq_t*)req->m_pRequest;
  msg.setString("UserName",
                uam.GetUserInfo().m_UserAccount);  // 用于查问题时区分用户请求
  msg.setString("IMQ_RequestType", "BOND_DEAL");
  for (std::list<xQBTradeCmpyInfo_c>::const_iterator it = pdata->m_List.begin();
       it != pdata->m_List.end(); ++it) {
    qb::proto::VariantMap msglist;
    int nID = 0;
    if (it->m_Id > 0) {
      bufferid[0] = '\0';
      sprintf(bufferid, "%d", it->m_Id);
      msglist.setString("IMQ_CompanyID", bufferid);
      nID = it->m_Id;
    } else {
      msglist.SetString("IMQ_CompanyID", it->m_BrokerID);
      nID = atoi(it->m_BrokerID);
    }
    if (strcmp(it->m_BrokerID, "e") != 0 && strcmp(it->m_BrokerID, "50") != 0) {
      msglist.setString("BusinessCode", "BOND");
      // 			if (!uam.IsBrokerBondAvailable(nID)) {
      // 				if (!uam.IsBrokerNCDAvailable(nID)) {
      // 					continue;
      // 				}
      // 				else {
      // 					msglist.setString("BusinessCode",
      // "NCD");
      // 				}
      // 			}
      // 			else {
      // 				if (!uam.IsBrokerNCDAvailable(nID)) {
      // 					msglist.setString("BusinessCode",
      // "BOND");
      // 				}
      // 			}
    }
    company_id_list.push_back(msglist);
  }
  msg.setList("IMQ_CompanyID", company_id_list);
  msg.setInt32("IMQ_VersionFrom", pdata->m_IndexFrom);
  msg.setInt32("IMQ_VersionTo", pdata->m_IndexTo);
  msg.setString("IMQ_BondKey", pdata->m_bondkey);
  msg.setString("IMQ_ListedMarket", pdata->m_listedmarket);
  msg.SetString("IMQ_traderID", pdata->m_traderId);
  msg.SetString("IMQ_exDeal", pdata->m_exDeal);
}

void qbbond::makeMarketStreamDealPush(qb::proto::Message& msg,
                                      qb::SSRequestMsg* req) {
  qb::proto::Message::List sublist;
  QBQuoteQuery_t* pdata = (QBQuoteQuery_t*)req->m_pRequest;
  for (std::list<TW_BOND>::const_iterator it = pdata->m_Bond.begin();
       it != pdata->m_Bond.end(); ++it) {
    qb::proto::VariantMap listmsg;
    listmsg.setString("Bond_Type", it->m_Bond_Type);
    listmsg.setString("BondID", it->m_BondID);
    listmsg.setString("BondKey", it->m_BondKey);
    listmsg.setString("ListedMarket", it->m_ListedMarket);
    sublist.push_back(listmsg);
  }
  qb::proto::VariantMap submsg;
  submsg.SetList("Bond", sublist);
  msg.SetMap("QBQuoteQuery", submsg);
}

void qbbond::makeExchangeQuoteReq(qb::proto::Message& msg,
                                  qb::SSRequestMsg* req) {
  qb::proto::Message::List company_id_list;
  qb::proto::Message::List key_list;
  qb::proto::VariantMap submsg;
  // char bufferid[32]={0};
  SSUserAccountManager& uam = SSUserAccountManager::instance();
  QBQuoteQuery_t* pdata = (QBQuoteQuery_t*)req->m_pRequest;
  msg.setString("UserName",
                uam.GetUserInfo().m_UserAccount);  // 用于查问题时区分用户请求
  msg.setString("IMQ_RequestType", "BONDOFFER_LIST");

  submsg.clear();
  switch (req->m_FuncID) {
    case E_FID_QB_EX_BEST_QUOTE_QUERY:
      submsg.setString("IMQ_CompanyID", "e");
      break;
    default:
      submsg.setString("IMQ_CompanyID", "50");
      break;
  }
  company_id_list.push_back(submsg);
  msg.setList("IMQ_CompanyID", company_id_list);
  for (std::list<TW_BOND>::const_iterator it = pdata->m_Bond.begin();
       it != pdata->m_Bond.end(); ++it) {
    submsg.clear();
    char tmpbuf[41] = {0};
    FIELDCOPY(tmpbuf, it->m_BondKey);
    std::string str(tmpbuf);
    str.append(it->m_ListedMarket);
    submsg.setString("IMQ_Key", str);
    key_list.push_back(submsg);
  }

  msg.setList("IMQ_Key", key_list);
}

void qbbond::notifyHisSingleDealByParam(const qb::SSAckMsg& msg,
                                        NotifyFunc notify) {
  std::string str;
  xSingleBondQuotationAck_c* pack =
      static_cast<xSingleBondQuotationAck_c*>(msg.m_pRet);
  if (pack) {
    str.append(pack->BondKey)
        .append("|")
        .append(pack->ListedMarket)
        .append("|")
        .append(pack->m_Source);
  }
  notify({msg.m_FuncID, str, nullptr}, msg);
}

void qbbond::notifyMktStreamByParam(const qb::SSAckMsg& msg,
                                    NotifyFunc notify) {
  std::map<std::string, xQBMarketStreamList_c> data;
  xQBMarketStreamList_c* pList = (xQBMarketStreamList_c*)(msg.m_pRet);
  std::list<xQBMarketStreamUnit_c>::iterator it = pList->m_List.begin();
  for (; it != pList->m_List.end(); it++) {
    QString str;
    if (strcmp(it->m_type, "1") == 0) {
      str = QString("%1|%2|%3")
                .arg(msg.m_FuncID)
                .arg(it->m_body1.m_bondkey)
                .arg(it->m_body1.m_listedmarket);
    } else if (strcmp(it->m_type, "2") == 0) {
      str = QString("%1|%2|%3")
                .arg(msg.m_FuncID)
                .arg(it->m_body2.m_bondkey)
                .arg(it->m_body2.m_listedmarket);
    } else {
      continue;
    }
    data[str.toStdString()].m_List.push_back(*it);
  }

  for (auto d : data) {
    SSAckMsg tmpMsg = msg;
    tmpMsg.m_pRet = (void*)&(d.second);
    notify({msg.m_FuncID, d.first, nullptr}, tmpMsg);
  }
}

void qbbond::notifyQuotePushByParam(const qb::SSAckMsg& msg,
                                    NotifyFunc notify) {
  std::map<std::string, xQBBestPriceListAck_c> data;
  xQBBestPriceListAck_c* pList = (xQBBestPriceListAck_c*)(msg.m_pRet);
  std::list<xQBBestPriceUnit_c>::iterator it = pList->m_List.begin();
  for (; it != pList->m_List.end(); it++) {
    QString str = QString("%1|%2|%3")
                      .arg(msg.m_FuncID)
                      .arg(it->m_bondkey)
                      .arg(it->m_listedmarket);
    data[str.toStdString()].m_List.push_back(*it);
  }

  for (auto d : data) {
    SSAckMsg tmpMsg = msg;
    tmpMsg.m_pRet = (void*)&(d.second);
    notify({msg.m_FuncID, d.first, nullptr}, tmpMsg);
  }
}

std::vector<std::string> qbbond::getMKTPushParams(int func,
                                                  const QBQuoteQuery_t& query) {
  std::vector<std::string> res;
  for (auto bond : query.m_Bond) {
    QString str = QString("%1|%2|%3")
                      .arg(func)
                      .arg(bond.m_BondKey)
                      .arg(bond.m_ListedMarket);
    res.push_back(str.toStdString());
  }
  return res;
}

void* qbbond::extractQBCDCPriceAllV3(const ProtoMessage& msg) {
  ProtoRaw rawvalue;
  if (!msg.GetRaw("CDCPrice", rawvalue)) return nullptr;

  if (!rawvalue.Data) return nullptr;

  // extract data
  char sBuffer[Y_RD_SERVICE_MESSAGE_BLOCK_LEN] = {0};
  int nLenOut = 0;
  if (!rdMessage::bUnZip((char*)rawvalue.Data, rawvalue.Length, sBuffer,
                         &nLenOut))
    return nullptr;

  // 按照字典格式解析数据
  char* sFileBuffer = sBuffer;
  size_t nStartPos, record_cnt, nFieldCnt;
  nStartPos = record_cnt = nFieldCnt = 0;
  std::vector<std::string> vHeaders;
  // parse headers
  std::string str;
  memcpy(&nStartPos, sFileBuffer + 4, 4);
  memcpy(&record_cnt, sFileBuffer + 8, 4);
  memcpy(&nFieldCnt, sFileBuffer + 12, 2);
  sFileBuffer += 14;
  for (int i = 0; i != nFieldCnt; ++i) {
    str = sFileBuffer;
    vHeaders.push_back(str);
    sFileBuffer = sFileBuffer + str.length() + 2;
  }
  sFileBuffer = sFileBuffer + 8;

  xQBACDCPriceList_c* ptr = new xQBACDCPriceList_c();
  xQBACDCPriceUnit_c cdcprice_unit;

  qb::base::CConvertFast convert;
  float fPrc = 0.0;
  double dPrc = 0.0;
  for (size_t i = 0; i != record_cnt; ++i) {
    memset(&cdcprice_unit, 0, sizeof(xQBACDCPriceUnit_c));
    for (size_t cnt = 0; cnt != vHeaders.size(); ++cnt) {
      ++sFileBuffer;
      if (CParserTool::IsStringEqual(vHeaders[cnt], "BondKey")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          FIELDCOPY(cdcprice_unit.m_bond_key, sFileBuffer);
          sFileBuffer = sFileBuffer + strlen(sFileBuffer) + 1;
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt], "ListedMarket")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          FIELDCOPY(cdcprice_unit.m_listedmarket, sFileBuffer);
          sFileBuffer = sFileBuffer + strlen(sFileBuffer) + 1;
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt], "CleanPrice")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          memcpy(&fPrc, sFileBuffer, sizeof(float));
          sFileBuffer += sizeof(float);
          FMTBUF(cdcprice_unit.m_CleanPrice, "%.4f", fPrc);
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt], "DurationX")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          memcpy(&dPrc, sFileBuffer, sizeof(double));
          sFileBuffer += sizeof(double);
          FMTBUF(cdcprice_unit.m_Duration, "%.4f", dPrc);
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt], "Yield")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          memcpy(&fPrc, sFileBuffer, sizeof(float));
          sFileBuffer += sizeof(float);
          FMTBUF(cdcprice_unit.m_Yield, "%.4f", fPrc);
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt], "Date")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          memcpy(&cdcprice_unit.m_Date, sFileBuffer, sizeof(unsigned int));
          sFileBuffer += sizeof(UINT);
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt], "EstOption")) {
        // 新增中债估值的含权属性,scofined.qi，在E_FID_QBA_CDC_PRICE_ALL_REQ中会处理
        if (!*sFileBuffer) {
          ++sFileBuffer;
          FIELDCOPY(cdcprice_unit.m_est_option, convert.ToGbk(sFileBuffer));
          sFileBuffer = sFileBuffer + strlen(sFileBuffer) + 1;
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt], "Authority")) {
        // 新增债券对应中债估值权限
        if (!*sFileBuffer) {
          ++sFileBuffer;
          memcpy(&cdcprice_unit.m_Authority, sFileBuffer, sizeof(int));
          sFileBuffer += sizeof(int);
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt], "FrontCleanPrice")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          memcpy(&fPrc, sFileBuffer, sizeof(float));
          sFileBuffer += sizeof(float);
          FMTBUF(cdcprice_unit.m_FrontCleanPrice, "%.4f", fPrc);
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt], "FrontYield")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          memcpy(&fPrc, sFileBuffer, sizeof(float));
          sFileBuffer += sizeof(float);
          FMTBUF(cdcprice_unit.m_FrontYield, "%.4f", fPrc);
        } else {
          ++sFileBuffer;
        }
      }
      ELSESKIP
    }
    sFileBuffer += 8;  // jump to next record;
    ptr->m_List.push_back(cdcprice_unit);
  }

  return ptr;
}

void* qbbond::extractQBBestPriceList(const ProtoMessage& msg) {
  ProtoList msglist;
  if (!msg.getList("IMQ_OUTCOME", msglist)) return nullptr;

  // SSAckMsg* pMsg = (SSAckMsg*)pData;
  // BLOGINFO("[MESSAGE]msglist count:%4d funcid:%d", msglist.size(),
  // pMsg->m_FuncID);

  xQBBestPriceListAck_c* ptr = new xQBBestPriceListAck_c();
  FIELDCOPY(ptr->m_BusinessCode, CParserTool::GetString(msg, "BusinessCode"));

  xQBBestPriceUnit_c bestprice_unit;
  std::string tmp;
  bool verbos = CParserTool::IsVerbosLogEnable();
  for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
       ++it) {
    if (it->Type != ProtoValue::VAR_MAP) continue;

    memset(&bestprice_unit, 0, sizeof(xQBBestPriceUnit_c));
    tmp.clear();
    const ProtoMap& msgmap = *it;

    // 调整字段的顺序,使得按照名称递增排序来访问,可以达到最高性能
    // 做法:查找	.*\"(\w+)\".*
    //		替换	\1\t\0
    //		选中然后排序
    FIELDCOPY(bestprice_unit.m_bondkey, CParserTool::GetString(msgmap, "bk"));
    FIELDCOPY(bestprice_unit.m_company_id,
              CParserTool::GetString(msgmap, "cid"));
    // FIELDCOPY(bestprice_unit.m_company_name, CParserTool::GetString(msgmap,
    // "cn"));
    CParserTool::MessageGetTime(msgmap, "ct", bestprice_unit.m_create_time);
    FIELDCOPY(bestprice_unit.m_desc_useless,
              CParserTool::GetString(msgmap, "desc"));
    FIELDCOPY(bestprice_unit.m_bp_status, CParserTool::GetString(msgmap, "ds"));
    FIELDCOPY(bestprice_unit.m_flag_bad,
              CParserTool::GetString(msgmap, "fbad"));
    FIELDCOPY(bestprice_unit.m_flag_bargain,
              CParserTool::GetString(msgmap, "fbar"));
    FIELDCOPY(bestprice_unit.m_fin_company_name,
              CParserTool::GetString(msgmap, "fcn"));
    FIELDCOPY(bestprice_unit.m_full_price,
              CParserTool::GetString(msgmap, "fp"));
    FIELDCOPY(bestprice_unit.m_flag_relation,
              CParserTool::GetString(msgmap, "fr"));
    FIELDCOPY(bestprice_unit.m_flag_vip, CParserTool::GetString(msgmap, "fv"));
    // FIELDCOPY(bestprice_unit.m_bond_code, CParserTool::GetString(msgmap,
    // "gc")); FIELDCOPY(bestprice_unit.m_bond_shorname,
    // CParserTool::GetString(msgmap, "gsn"));
    FIELDCOPY(bestprice_unit.m_id, CParserTool::GetString(msgmap, "id"));
    FIELDCOPY(bestprice_unit.m_trade_clear_Price,
              CParserTool::GetString(msgmap, "ldnp"));
    FIELDCOPY(bestprice_unit.m_tradePrice,
              CParserTool::GetString(msgmap, "ldp"));
    FIELDCOPY(bestprice_unit.m_listedmarket,
              CParserTool::GetString(msgmap, "lm"));
    CParserTool::MessageGetTime(msgmap, "mt", bestprice_unit.m_modify_time);
    FIELDCOPY(bestprice_unit.m_clean_price,
              CParserTool::GetString(msgmap, "np"));
    FIELDCOPY(bestprice_unit.m_price_description,
              CParserTool::GetString(msgmap, "pdesc"));
    FIELDCOPY(bestprice_unit.m_price, CParserTool::GetString(msgmap, "pri"));
    FIELDCOPY(bestprice_unit.m_price_status,
              CParserTool::GetString(msgmap, "ps"));
    FIELDCOPY(bestprice_unit.m_quotetype, CParserTool::GetString(msgmap, "qt"));
    FIELDCOPY(bestprice_unit.m_rebate, CParserTool::GetString(msgmap, "reb"));
    FIELDCOPY(bestprice_unit.m_return_point,
              CParserTool::GetString(msgmap, "rp"));
    FIELDCOPY(bestprice_unit.m_status, CParserTool::GetString(msgmap, "sts"));
    FIELDCOPY(bestprice_unit.m_symbol, CParserTool::GetString(msgmap, "sym"));
    msgmap.GetInt32("ver", bestprice_unit.m_version);
    FIELDCOPY(bestprice_unit.m_volume, CParserTool::GetString(msgmap, "vol"));
    FIELDCOPY(bestprice_unit.m_yield, CParserTool::GetString(msgmap, "yd"));

    ptr->m_List.push_back(bestprice_unit);
  }

  ProtoMap extrmsgmap;
  if (msg.GetMap("IMQ_EXTRAINFO", extrmsgmap)) {
    ProtoList extrmsglist;
    if (extrmsgmap.getList("Version_List", extrmsglist)) {
      xQBBestPriceVersionUnit_c version_unit;
      for (ProtoList::const_iterator it = extrmsglist.begin();
           it != extrmsglist.end(); ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(&version_unit, 0, sizeof(xQBBestPriceVersionUnit_c));
        const ProtoMap& msgmap = *it;

        FIELDCOPY(version_unit.m_company_id,
                  CParserTool::GetString(msgmap, "BF_CompanyID"));
        msgmap.GetInt32("BF_Version", version_unit.m_version);

        ptr->m_extList.push_back(version_unit);
      }
    }
  }
  return ptr;
}

#ifndef WIN32
#define _atoi64(val) strtoll(val, NULL, 10)
#endif

void* qbbond::extractQBExQuoteList(const ProtoMessage& msg) {
  ProtoList msglist;
  if (!msg.getList("IMQ_OUTCOME", msglist)) return nullptr;

  xQBExQuoteList_c* ptr = new xQBExQuoteList_c();

  char buff[256] = {0};
  for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
       ++it) {
    if (it->Type != ProtoValue::VAR_MAP) continue;
    xQBExQuoteUnit_c unit;

    const ProtoMap& msgmap = *it;

    // memset(buff, 0, sizeof(buff));
    FIELDCOPY(buff, CParserTool::GetString(msgmap, "createTime"));
    unit.m_time = _atoi64(buff);
    FIELDCOPY(unit.m_BondKey, CParserTool::GetString(msgmap, "bondKey"));
    FIELDCOPY(unit.m_ListedMarket,
              CParserTool::GetString(msgmap, "listedMarket"));

    // 卖五
    QBExQuote5& quoteb5 = unit.m_Quote5[0];
    FIELDCOPY(quoteb5.m_YTE, CParserTool::GetString(msgmap, "ofr5ytc"));
    FIELDCOPY(quoteb5.m_YTM, CParserTool::GetString(msgmap, "ofr5yield"));
    FIELDCOPY(quoteb5.m_NetPrice,
              CParserTool::GetString(msgmap, "ofr5netPrice"));
    FIELDCOPY(quoteb5.m_Vol, CParserTool::GetString(msgmap, "ofr5volume"));
    // 卖四
    QBExQuote5& quoteb4 = unit.m_Quote5[1];
    FIELDCOPY(quoteb4.m_YTE, CParserTool::GetString(msgmap, "ofr4ytc"));
    FIELDCOPY(quoteb4.m_YTM, CParserTool::GetString(msgmap, "ofr4yield"));
    FIELDCOPY(quoteb4.m_NetPrice,
              CParserTool::GetString(msgmap, "ofr4netPrice"));
    FIELDCOPY(quoteb4.m_Vol, CParserTool::GetString(msgmap, "ofr4volume"));
    // 卖三
    QBExQuote5& quoteb3 = unit.m_Quote5[2];
    FIELDCOPY(quoteb3.m_YTE, CParserTool::GetString(msgmap, "ofr3ytc"));
    FIELDCOPY(quoteb3.m_YTM, CParserTool::GetString(msgmap, "ofr3yield"));
    FIELDCOPY(quoteb3.m_NetPrice,
              CParserTool::GetString(msgmap, "ofr3netPrice"));
    FIELDCOPY(quoteb3.m_Vol, CParserTool::GetString(msgmap, "ofr3volume"));
    // 卖二
    QBExQuote5& quoteb2 = unit.m_Quote5[3];
    FIELDCOPY(quoteb2.m_YTE, CParserTool::GetString(msgmap, "ofr2ytc"));
    FIELDCOPY(quoteb2.m_YTM, CParserTool::GetString(msgmap, "ofr2yield"));
    FIELDCOPY(quoteb2.m_NetPrice,
              CParserTool::GetString(msgmap, "ofr2netPrice"));
    FIELDCOPY(quoteb2.m_Vol, CParserTool::GetString(msgmap, "ofr2volume"));
    // 卖一
    QBExQuote5& quoteb1 = unit.m_Quote5[4];
    FIELDCOPY(quoteb1.m_YTE, CParserTool::GetString(msgmap, "ofr1ytc"));
    FIELDCOPY(quoteb1.m_YTM, CParserTool::GetString(msgmap, "ofr1yield"));
    FIELDCOPY(quoteb1.m_NetPrice,
              CParserTool::GetString(msgmap, "ofr1netPrice"));
    FIELDCOPY(quoteb1.m_Vol, CParserTool::GetString(msgmap, "ofr1volume"));
    // 买一
    QBExQuote5& quotes1 = unit.m_Quote5[5];
    FIELDCOPY(quotes1.m_YTE, CParserTool::GetString(msgmap, "bid1ytc"));
    FIELDCOPY(quotes1.m_YTM, CParserTool::GetString(msgmap, "bid1yield"));
    FIELDCOPY(quotes1.m_NetPrice,
              CParserTool::GetString(msgmap, "bid1netPrice"));
    FIELDCOPY(quotes1.m_Vol, CParserTool::GetString(msgmap, "bid1volume"));
    // 买二
    QBExQuote5& quotes2 = unit.m_Quote5[6];
    FIELDCOPY(quotes2.m_YTE, CParserTool::GetString(msgmap, "bid2ytc"));
    FIELDCOPY(quotes2.m_YTM, CParserTool::GetString(msgmap, "bid2yield"));
    FIELDCOPY(quotes2.m_NetPrice,
              CParserTool::GetString(msgmap, "bid2netPrice"));
    FIELDCOPY(quotes2.m_Vol, CParserTool::GetString(msgmap, "bid2volume"));
    // 买三
    QBExQuote5& quotes3 = unit.m_Quote5[7];
    FIELDCOPY(quotes3.m_YTE, CParserTool::GetString(msgmap, "bid3ytc"));
    FIELDCOPY(quotes3.m_YTM, CParserTool::GetString(msgmap, "bid3yield"));
    FIELDCOPY(quotes3.m_NetPrice,
              CParserTool::GetString(msgmap, "bid3netPrice"));
    FIELDCOPY(quotes3.m_Vol, CParserTool::GetString(msgmap, "bid3volume"));
    // 买四
    QBExQuote5& quotes4 = unit.m_Quote5[8];
    FIELDCOPY(quotes4.m_YTE, CParserTool::GetString(msgmap, "bid4ytc"));
    FIELDCOPY(quotes4.m_YTM, CParserTool::GetString(msgmap, "bid4yield"));
    FIELDCOPY(quotes4.m_NetPrice,
              CParserTool::GetString(msgmap, "bid4netPrice"));
    FIELDCOPY(quotes4.m_Vol, CParserTool::GetString(msgmap, "bid4volume"));
    // 买五
    QBExQuote5& quotes5 = unit.m_Quote5[9];
    FIELDCOPY(quotes5.m_YTE, CParserTool::GetString(msgmap, "bid5ytc"));
    FIELDCOPY(quotes5.m_YTM, CParserTool::GetString(msgmap, "bid5yield"));
    FIELDCOPY(quotes5.m_NetPrice,
              CParserTool::GetString(msgmap, "bid5netPrice"));
    FIELDCOPY(quotes5.m_Vol, CParserTool::GetString(msgmap, "bid5volume"));

    ptr->m_List.push_back(unit);
  }

  return ptr;
}

void* qbbond::extractQBExQuoteListSimplify(const ProtoMessage& msg) {
  ProtoList msglist;
  if (!msg.getList("IMQ_OUTCOME", msglist)) return nullptr;

  xQBExQuoteList_c* ptr = new xQBExQuoteList_c();

  char buff[256] = {0};
  for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
       ++it) {
    if (it->Type != ProtoValue::VAR_MAP) continue;
    xQBExQuoteUnit_c unit;

    const ProtoMap& msgmap = *it;

    memset(buff, 0, sizeof(buff));
    FIELDCOPY(buff, CParserTool::GetString(msgmap, "ct"));
    unit.m_time = _atoi64(buff);
    FIELDCOPY(unit.m_BondKey, CParserTool::GetString(msgmap, "bk"));
    FIELDCOPY(unit.m_ListedMarket, CParserTool::GetString(msgmap, "lm"));

    // 卖五
    QBExQuote5& quoteb5 = unit.m_Quote5[0];
    FIELDCOPY(quoteb5.m_YTE, CParserTool::GetString(msgmap, "o5e"));
    FIELDCOPY(quoteb5.m_YTM, CParserTool::GetString(msgmap, "o5d"));
    FIELDCOPY(quoteb5.m_NetPrice, CParserTool::GetString(msgmap, "o5n"));
    FIELDCOPY(quoteb5.m_Vol, CParserTool::GetString(msgmap, "o5v"));
    // 卖四
    QBExQuote5& quoteb4 = unit.m_Quote5[1];
    FIELDCOPY(quoteb4.m_YTE, CParserTool::GetString(msgmap, "o4e"));
    FIELDCOPY(quoteb4.m_YTM, CParserTool::GetString(msgmap, "o4d"));
    FIELDCOPY(quoteb4.m_NetPrice, CParserTool::GetString(msgmap, "o4n"));
    FIELDCOPY(quoteb4.m_Vol, CParserTool::GetString(msgmap, "o4v"));
    // 卖三
    QBExQuote5& quoteb3 = unit.m_Quote5[2];
    FIELDCOPY(quoteb3.m_YTE, CParserTool::GetString(msgmap, "o3e"));
    FIELDCOPY(quoteb3.m_YTM, CParserTool::GetString(msgmap, "o3d"));
    FIELDCOPY(quoteb3.m_NetPrice, CParserTool::GetString(msgmap, "o3n"));
    FIELDCOPY(quoteb3.m_Vol, CParserTool::GetString(msgmap, "o3v"));
    // 卖二
    QBExQuote5& quoteb2 = unit.m_Quote5[3];
    FIELDCOPY(quoteb2.m_YTE, CParserTool::GetString(msgmap, "o2e"));
    FIELDCOPY(quoteb2.m_YTM, CParserTool::GetString(msgmap, "o2d"));
    FIELDCOPY(quoteb2.m_NetPrice, CParserTool::GetString(msgmap, "o2n"));
    FIELDCOPY(quoteb2.m_Vol, CParserTool::GetString(msgmap, "o2v"));
    // 卖一
    QBExQuote5& quoteb1 = unit.m_Quote5[4];
    FIELDCOPY(quoteb1.m_YTE, CParserTool::GetString(msgmap, "o1e"));
    FIELDCOPY(quoteb1.m_YTM, CParserTool::GetString(msgmap, "o1d"));
    FIELDCOPY(quoteb1.m_NetPrice, CParserTool::GetString(msgmap, "o1n"));
    FIELDCOPY(quoteb1.m_Vol, CParserTool::GetString(msgmap, "o1v"));
    // 买一
    QBExQuote5& quotes1 = unit.m_Quote5[5];
    FIELDCOPY(quotes1.m_YTE, CParserTool::GetString(msgmap, "b1e"));
    FIELDCOPY(quotes1.m_YTM, CParserTool::GetString(msgmap, "b1d"));
    FIELDCOPY(quotes1.m_NetPrice, CParserTool::GetString(msgmap, "b1n"));
    FIELDCOPY(quotes1.m_Vol, CParserTool::GetString(msgmap, "b1v"));
    // 买二
    QBExQuote5& quotes2 = unit.m_Quote5[6];
    FIELDCOPY(quotes2.m_YTE, CParserTool::GetString(msgmap, "b2e"));
    FIELDCOPY(quotes2.m_YTM, CParserTool::GetString(msgmap, "b2d"));
    FIELDCOPY(quotes2.m_NetPrice, CParserTool::GetString(msgmap, "b2n"));
    FIELDCOPY(quotes2.m_Vol, CParserTool::GetString(msgmap, "b2v"));
    // 买三
    QBExQuote5& quotes3 = unit.m_Quote5[7];
    FIELDCOPY(quotes3.m_YTE, CParserTool::GetString(msgmap, "b3e"));
    FIELDCOPY(quotes3.m_YTM, CParserTool::GetString(msgmap, "b3d"));
    FIELDCOPY(quotes3.m_NetPrice, CParserTool::GetString(msgmap, "b3n"));
    FIELDCOPY(quotes3.m_Vol, CParserTool::GetString(msgmap, "b3v"));
    // 买四
    QBExQuote5& quotes4 = unit.m_Quote5[8];
    FIELDCOPY(quotes4.m_YTE, CParserTool::GetString(msgmap, "b4e"));
    FIELDCOPY(quotes4.m_YTM, CParserTool::GetString(msgmap, "b4d"));
    FIELDCOPY(quotes4.m_NetPrice, CParserTool::GetString(msgmap, "b4n"));
    FIELDCOPY(quotes4.m_Vol, CParserTool::GetString(msgmap, "b4v"));
    // 买五
    QBExQuote5& quotes5 = unit.m_Quote5[9];
    FIELDCOPY(quotes5.m_YTE, CParserTool::GetString(msgmap, "b5e"));
    FIELDCOPY(quotes5.m_YTM, CParserTool::GetString(msgmap, "b5d"));
    FIELDCOPY(quotes5.m_NetPrice, CParserTool::GetString(msgmap, "b5n"));
    FIELDCOPY(quotes5.m_Vol, CParserTool::GetString(msgmap, "b5v"));

    ptr->m_List.push_back(unit);
  }

  return ptr;
}

void* qbbond::extractQBSHFIQuoteList(const ProtoMessage& msg) {
  ProtoList msglist;
  if (!msg.getList("List", msglist)) return nullptr;

  xQBSHFIQuoteList_c* ptr = new xQBSHFIQuoteList_c();

  for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
       ++it) {
    if (it->Type != ProtoValue::VAR_MAP) continue;
    xQBSHFIQuoteUnit_c unit;

    const ProtoMap& msgmap = *it;

    CParserTool::MessageGetInt64toTime(msgmap, "Time", unit.m_Time);
    FIELDCOPY(unit.m_BondKey, CParserTool::GetString(msgmap, "BondKey"));
    FIELDCOPY(unit.m_ListedMarket,
              CParserTool::GetString(msgmap, "ListedMarket"));
    msgmap.GetInt32("Index", unit.m_Index);
    FIELDCOPY(unit.m_BrokerID, CParserTool::GetString(msgmap, "BrokerID"));

    // Bid
    ProtoMap msgBidMap;
    msgmap.GetMap("Bid", msgBidMap);

    QBSHFIQuote5& quoteBid = unit.m_Bid;
    FIELDCOPY(quoteBid.m_Yield, CParserTool::GetString(msgBidMap, "Yield"));
    FIELDCOPY(quoteBid.m_Price, CParserTool::GetString(msgBidMap, "Price"));
    FIELDCOPY(quoteBid.m_Vol, CParserTool::GetString(msgBidMap, "Vol"));
    FIELDCOPY(quoteBid.m_ExerciseFlag,
              CParserTool::GetString(msgBidMap, "ExerciseFlag"));
    FIELDCOPY(quoteBid.m_Institution,
              CParserTool::GetString(msgBidMap, "Institution"));

    // Ofr
    ProtoMap msgOfrMap;
    msgmap.GetMap("Ofr", msgOfrMap);

    QBSHFIQuote5& quoteOfr = unit.m_Ofr;
    FIELDCOPY(quoteOfr.m_Yield, CParserTool::GetString(msgOfrMap, "Yield"));
    FIELDCOPY(quoteOfr.m_Price, CParserTool::GetString(msgOfrMap, "Price"));
    FIELDCOPY(quoteOfr.m_Vol, CParserTool::GetString(msgOfrMap, "Vol"));
    FIELDCOPY(quoteOfr.m_ExerciseFlag,
              CParserTool::GetString(msgOfrMap, "ExerciseFlag"));
    FIELDCOPY(quoteOfr.m_Institution,
              CParserTool::GetString(msgOfrMap, "Institution"));

    ptr->m_List.push_back(unit);
  }
  return ptr;
}

void* qbbond::extractQBBondCreditSpreadAck(const ProtoMessage& msg) {
  xQBBondCreditSpreadAck* ptr = new xQBBondCreditSpreadAck();
  FIELDCOPY(ptr->m_bond_key, CParserTool::GetString(msg, "bond_key"));
  FIELDCOPY(ptr->m_listed_market, CParserTool::GetString(msg, "listed_market"));
  ProtoList ackList;
  if (msg.GetList("list", ackList)) {
    extractCreditAckList(ackList, ptr->m_list);
  }

  return ptr;
}

void* qbbond::extractQBIssuerCreditSpreadAck(const ProtoMessage& msg) {
  xQBIssuerCreditSpreadAck* ptr = new xQBIssuerCreditSpreadAck();
  FIELDCOPY(ptr->m_issuer_code, CParserTool::GetString(msg, "issuer_code"));
  ProtoList ackList;
  if (msg.GetList("list", ackList)) {
    extractCreditAckList(ackList, ptr->m_list);
  }

  return ptr;
}

void qbbond::extractCreditAckList(
    const ProtoList& ackList, std::list<xQBBondCreditSpreadAckUnit>& listData) {
  for (ProtoList::const_iterator it = ackList.begin(); it != ackList.end();
       ++it) {
    if (it->Type != ProtoValue::VAR_MAP) continue;
    const ProtoMap& mgUnit = *it;
    xQBBondCreditSpreadAckUnit unit;
    mgUnit.GetInt32("dt", unit.m_date);
    FIELDCOPY(unit.m_spread, CParserTool::GetString(mgUnit, "sp"));
    FIELDCOPY(unit.m_espread, CParserTool::GetString(mgUnit, "ep"));
    FIELDCOPY(unit.m_rating_change_flag, CParserTool::GetString(mgUnit, "rcf"));
    FIELDCOPY(unit.m_rating_prev, CParserTool::GetString(mgUnit, "rp"));
    FIELDCOPY(unit.m_rating_cur, CParserTool::GetString(mgUnit, "rc"));
    FIELDCOPY(unit.m_issuerCode, CParserTool::GetString(mgUnit, "ic"));
    FIELDCOPY(unit.m_yield_avg, CParserTool::GetString(mgUnit, "av"));
    FIELDCOPY(unit.m_gk_Yield, CParserTool::GetString(mgUnit, "gk"));
    FIELDCOPY(unit.m_zz_Yield, CParserTool::GetString(mgUnit, "zz"));
    FIELDCOPY(unit.m_Val_Yield, CParserTool::GetString(mgUnit, "vy"));
    listData.push_back(unit);
  }
}

void* qbbond::extractBestPriceSynthetical(const ProtoMessage& msg) {
  xQBBestPriceSyntheticalAck_c* ptr = new xQBBestPriceSyntheticalAck_c();
  FIELDCOPY(ptr->m_bondkey, CParserTool::GetString(msg, "bk"));
  FIELDCOPY(ptr->m_listedmarket, CParserTool::GetString(msg, "lm"));
  CParserTool::MessageGetTime(msg, "tm", ptr->m_time);
  msg.GetInt32("ver", ptr->m_version);
  ProtoMap mapBid, mapOfr;
  if (msg.GetMap("bid", mapBid)) {
    FIELDCOPY(ptr->m_bid.m_id, CParserTool::GetString(mapBid, "id"));
    FIELDCOPY(ptr->m_bid.m_price, CParserTool::GetString(mapBid, "pri"));
    FIELDCOPY(ptr->m_bid.m_quotetype, CParserTool::GetString(mapBid, "qt"));
    FIELDCOPY(ptr->m_bid.m_clean_price, CParserTool::GetString(mapBid, "np"));
    FIELDCOPY(ptr->m_bid.m_full_price, CParserTool::GetString(mapBid, "fp"));
    FIELDCOPY(ptr->m_bid.m_yield, CParserTool::GetString(mapBid, "yd"));
    FIELDCOPY(ptr->m_bid.m_volume, CParserTool::GetString(mapBid, "vol"));
    FIELDCOPY(ptr->m_bid.m_bp_status, CParserTool::GetString(mapBid, "ds"));
  }
  if (msg.GetMap("ofr", mapOfr)) {
    FIELDCOPY(ptr->m_ofr.m_id, CParserTool::GetString(mapOfr, "id"));
    FIELDCOPY(ptr->m_ofr.m_price, CParserTool::GetString(mapOfr, "pri"));
    FIELDCOPY(ptr->m_ofr.m_quotetype, CParserTool::GetString(mapOfr, "qt"));
    FIELDCOPY(ptr->m_ofr.m_clean_price, CParserTool::GetString(mapOfr, "np"));
    FIELDCOPY(ptr->m_ofr.m_full_price, CParserTool::GetString(mapOfr, "fp"));
    FIELDCOPY(ptr->m_ofr.m_yield, CParserTool::GetString(mapOfr, "yd"));
    FIELDCOPY(ptr->m_ofr.m_volume, CParserTool::GetString(mapOfr, "vol"));
    FIELDCOPY(ptr->m_ofr.m_bp_status, CParserTool::GetString(mapOfr, "ds"));
  }

  return ptr;
}

void* qbbond::extractCsiV2(const ProtoMessage& msg) {
  ProtoRaw rawvalue;
  if (!msg.GetRaw("CSIPrice", rawvalue)) return nullptr;

  if (!rawvalue.Data) return nullptr;

  // extract data
  static char sBuffer[Y_RD_SERVICE_MESSAGE_BLOCK_LEN] = {0};

  int nLenOut = 0;
  if (!rdMessage::bUnZip((char*)rawvalue.Data, rawvalue.Length, sBuffer,
                         &nLenOut))
    return nullptr;

  // 按照字典格式解析数据
  char* sFileBuffer = sBuffer;
  size_t nStartPos, record_cnt, nFieldCnt;
  nStartPos = record_cnt = nFieldCnt = 0;
  std::vector<std::string> vHeaders;
  // parse headers
  std::string str;
  memcpy_s(&nStartPos, sizeof(unsigned int), sFileBuffer + 4, 4);
  memcpy_s(&record_cnt, sizeof(unsigned int), sFileBuffer + 8, 4);
  memcpy_s(&nFieldCnt, sizeof(unsigned int), sFileBuffer + 12, 2);
  sFileBuffer += 14;
  vHeaders.reserve(nFieldCnt);
  for (int i = 0; i != nFieldCnt; ++i) {
    str = sFileBuffer;
    sFileBuffer = sFileBuffer + str.length() + 2;
    vHeaders.emplace_back(str);
  }
  sFileBuffer = sFileBuffer + 8;

  xCSIList_c* ptr = new xCSIList_c();
  xCSIUint_c csi_unit;

  double dPrc = 0;

  //`Bond_Key`, `Listed_Market`, `Clean_Price_Maturity`, `Yld_To_Maturity`,
  //`Modified_Duration_Maturity`, `Clean_Price_Exercise`, `Yld_To_Exercise`,
  //`Modified_Duration_Exercise`, `Date`
  for (size_t i = 0; i != record_cnt; ++i) {
    memset(&csi_unit, 0, sizeof(xCSIUint_c));
    for (size_t cnt = 0; cnt != vHeaders.size(); ++cnt) {
      ++sFileBuffer;
      if (CParserTool::IsStringEqual(vHeaders[cnt], "Bond_Key")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          FIELDCOPY(csi_unit.m_bond_key, sFileBuffer);
          sFileBuffer = sFileBuffer + strlen(sFileBuffer) + 1;
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt], "Listed_Market")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          FIELDCOPY(csi_unit.m_listedmarket, sFileBuffer);
          sFileBuffer = sFileBuffer + strlen(sFileBuffer) + 1;
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt],
                                            "Clean_Price_Maturity")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          memcpy_s(&dPrc, sizeof(double), sFileBuffer, sizeof(double));
          csi_unit.m_dCleanPriceMaturity = dPrc;
          sFileBuffer += sizeof(double);
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt], "Yld_To_Maturity")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          memcpy_s(&dPrc, sizeof(double), sFileBuffer, sizeof(double));
          csi_unit.m_dYieldToMaturity = dPrc;
          sFileBuffer += sizeof(double);
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt],
                                            "Modified_Duration_Maturity")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          memcpy_s(&dPrc, sizeof(double), sFileBuffer, sizeof(double));
          csi_unit.m_dModifiedDurationMarturity = dPrc;
          sFileBuffer += sizeof(double);
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt],
                                            "Clean_Price_Exercise")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          memcpy_s(&dPrc, sizeof(double), sFileBuffer, sizeof(double));
          csi_unit.m_dCleanPriceExercise = dPrc;
          sFileBuffer += sizeof(double);
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt], "Yld_To_Exercise")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          memcpy_s(&dPrc, sizeof(double), sFileBuffer, sizeof(double));
          csi_unit.m_dYieldToExercise = dPrc;
          sFileBuffer += sizeof(double);
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt],
                                            "Modified_Duration_Exercise")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          memcpy_s(&dPrc, sizeof(double), sFileBuffer, sizeof(double));
          csi_unit.m_dModifiedDurationExercise = dPrc;
          sFileBuffer += sizeof(double);
        } else {
          ++sFileBuffer;
        }
      } else if (CParserTool::IsStringEqual(vHeaders[cnt], "Date")) {
        if (!*sFileBuffer) {
          ++sFileBuffer;
          double date = 0;
          memcpy_s(&date, sizeof(double), sFileBuffer, sizeof(double));
          csi_unit.m_nDate = (UINT)date;
          sFileBuffer += sizeof(double);
        } else {
          ++sFileBuffer;
        }
      } else {
        // skip buffer because cannot match header name in vHeaders
        if (*sFileBuffer) {
          ++sFileBuffer;
        } else {
          --sFileBuffer;
          if (*sFileBuffer == SSTYPE_STRING) {
            sFileBuffer += 2;
            while (*sFileBuffer++);
          } else if (*sFileBuffer == SSTYPE_FLOAT) {
            sFileBuffer += 6;
            while (*sFileBuffer++);
          } else if (*sFileBuffer == SSTYPE_DOUBLE) {
            sFileBuffer += 10;
          } else if (*sFileBuffer == SSTYPE_INT32) {
            sFileBuffer += 6;
          }
        }
      }
    }
    sFileBuffer += 8;  // jump to next record;
    ptr->m_List.push_back(csi_unit);
  }

  return ptr;
}

void* qbbond::extractQBBondLiquidityFullAck_TableCodec(
    const ProtoMessage& msg) {
  qb::base::msg::Raw raw;
  if (!msg.GetRaw("List", raw)) return nullptr;

  qb::proto::VariantTableDecoder subList;
  if (!subList.decode((const char*)raw.Data, raw.Length)) return nullptr;

  xQBBondLiquidityFullAck_c* ptr = new xQBBondLiquidityFullAck_c();

  for (auto itr = subList.begin(); itr != subList.end(); ++itr) {
    const qb::proto::VariantRecord* recode = *itr;
    xQBBondLiquidityUnit unit;
    memset(&unit, 0, sizeof(unit));
    FIELDCOPY(unit.m_bondkey, CParserTool::GetString(recode, "bondkey"));
    FIELDCOPY(unit.m_listedmarket,
              CParserTool::GetString(recode, "listedmarket"));
    FIELDCOPY(unit.m_liquidLevel,
              CParserTool::GetString(recode, "liquidLevel"));
    FIELDCOPY(unit.m_liquid, CParserTool::GetString(recode, "liquid"));
    ptr->m_List.push_back(unit);
  }

  return ptr;
}

void* qbbond::extractQBIssuerLiquidityFullAck_TableCodec(
    const ProtoMessage& msg) {
  qb::base::msg::Raw raw;
  if (!msg.GetRaw("List", raw)) return nullptr;

  qb::proto::VariantTableDecoder subList;
  if (!subList.decode((const char*)raw.Data, raw.Length)) return nullptr;

  xQBIssuerLiquidityFullAck_c* ptr = new xQBIssuerLiquidityFullAck_c();

  for (auto itr = subList.begin(); itr != subList.end(); ++itr) {
    const qb::proto::VariantRecord* recode = *itr;
    xQBIssuerLiquidityUnit unit;
    memset(&unit, 0, sizeof(unit));
    FIELDCOPY(unit.m_IssuerCode, CParserTool::GetString(recode, "IssuerCode"));
    FIELDCOPY(unit.m_liquidLevel,
              CParserTool::GetString(recode, "liquidLevel"));
    FIELDCOPY(unit.m_liquid, CParserTool::GetString(recode, "liquid"));
    ptr->m_List.push_back(unit);
  }

  return ptr;
}

void* qbbond::extractQBHighYieldBondListAck(const ProtoMessage& msg) {
  ProtoList msgList;
  if (!msg.getList("List", msgList)) return nullptr;
  xQBHighYieldBondListAck_c* ptr = new xQBHighYieldBondListAck_c();
  int nSize = 0;
  QBHighYieldBond unit;
  for (ProtoList::const_iterator it = msgList.begin(); it != msgList.end();
       ++it) {
    if (it->Type != qb::proto::Variant::VAR_MAP) continue;
    const ProtoMap& msgmap = *it;
    memset(&unit, 0, sizeof(_tag_QBHighYieldBond));
    FIELDCOPY(unit.m_bondkey, CParserTool::GetString(msgmap, "bondkey"));
    FIELDCOPY(unit.m_listedmarket,
              CParserTool::GetString(msgmap, "listedmarket"));
    ptr->m_List.push_back(unit);
  }

  return ptr;
}

void* qbbond::extractQBThirdPartyGuaranteeListAck(const ProtoMessage& msg) {
  ProtoRaw rawvalue;
  if (!msg.GetRaw("RawData", rawvalue)) {
    return nullptr;
  }

  if (!rawvalue.Data) {
    return nullptr;
  }

  // extract data
  DECODE_RAWHEAD;

  xQBThirdPartyGuaranteeListAck_c* ptr = new xQBThirdPartyGuaranteeListAck_c();
  QBThirdPartyGuarantee unit;
  for (size_t i = 0; i != record_cnt; ++i) {
    memset(&unit, 0, sizeof(_tagQBThirdPartyGuarantee));
    for (size_t cnt = 0; cnt != vHeaders.size(); ++cnt) {
      ++sFileBuffer;
      IFHEAD("bk") { GETITEM_STRING_UTF8(m_bondkey); }
      else IFHEAD("lm") {
        GETITEM_STRING_UTF8(m_listedmarket);
      }
      else IFHEAD("ic") {
        GETITEM_STRING_UTF8(m_institution_code);
      }
      else IFHEAD("ar") {
        GETITEM_STRING_UTF8(m_area);
      }
      ELSESKIP
    }
    sFileBuffer += 8;  // jump to next record;
    ptr->m_List.push_back(unit);
  }

  return ptr;
}

void* qbbond::extractSectorBondAck(const ProtoMessage& msg) {
  ProtoRaw rawvalue;
  if (!msg.GetRaw("RawData", rawvalue)) {
    return nullptr;
  }

  if (!rawvalue.Data) {
    return nullptr;
  }

  // extract data
  DECODE_RAWHEAD;

  SectorBondAck* ptr = new SectorBondAck();
  SectorBondUnit unit;
  for (size_t i = 0; i != record_cnt; ++i) {
    memset(&unit, 0, sizeof(SectorBondUnit));
    for (size_t cnt = 0; cnt != vHeaders.size(); ++cnt) {
      ++sFileBuffer;
      IFHEAD("bc") { GETITEM_STRING_UTF8(m_comBondCode); }
      else IFHEAD("sc") {
        GETITEM_STRING_UTF8(m_sectorCode);
      }
      ELSESKIP
    }
    sFileBuffer += 8;  // jump to next record;
    ptr->m_bondList.push_back(unit);
  }

  return ptr;
}

void* qbbond::extractMarketMakeTarget(const ProtoMessage& msg) {
  xQBMarketMakeTargetAck_c* ptr = new xQBMarketMakeTargetAck_c();
  ProtoList msglist;
  if (!msg.getList("list", msglist)) return nullptr;

  for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
       ++it) {
    const ProtoMap& msgmap = *it;

    xQBMarketMakeTargetUnit_c unit;
    memset(&unit, 0, sizeof(xQBMarketMakeTargetUnit_c));

    FIELDCOPY(unit.m_sectionId, CParserTool::GetString(msgmap, "sectionId"));
    FIELDCOPY(unit.m_comBondCode,
              CParserTool::GetString(msgmap, "comBondCode"));
    ptr->m_list.push_back(unit);
  }

  return ptr;
}

void* qbbond::extractQBBondSSInfoNewList(const ProtoMessage& msg) {
  ProtoList msglist;
  if (!msg.getList("List", msglist)) return nullptr;

  xQBBondSSInfoNewListAck_c* ptr = new xQBBondSSInfoNewListAck_c();

  for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
       ++it) {
    if (it->Type != ProtoValue::VAR_MAP) continue;
    const ProtoMap& msgmap = *it;
    xBondSSInfoNew_c ssbondinfor_unit;

    FIELDCOPY(ssbondinfor_unit.m_BondKey,
              CParserTool::GetString(msgmap, "BondKey"));
    FIELDCOPY(ssbondinfor_unit.m_BondListed_Market,
              CParserTool::GetString(msgmap, "BondListed_Market"));
    FIELDCOPY(ssbondinfor_unit.m_BondID,
              CParserTool::GetString(msgmap, "BondID"));
    FIELDCOPY(ssbondinfor_unit.m_Short_Name,
              CParserTool::GetString(msgmap, "Short_Name"));
    FIELDCOPY(ssbondinfor_unit.m_Full_Name,
              CParserTool::GetString(msgmap, "Full_Name"));
    FIELDCOPY(ssbondinfor_unit.m_Issuer_Rating_Current,
              CParserTool::GetString(msgmap, "Issuer_Rating_Current"));
    FIELDCOPY(ssbondinfor_unit.m_Rating_Current,
              CParserTool::GetString(msgmap, "Rating_Current"));
    FIELDCOPY(ssbondinfor_unit.m_Issuer_Rating_Dept,
              CParserTool::GetString(msgmap, "Issuer_Rating_Dept"));
    FIELDCOPY(ssbondinfor_unit.m_Rating_Current_Dept,
              CParserTool::GetString(msgmap, "Rating_Current_Dept"));
    FIELDCOPY(ssbondinfor_unit.m_Bond_Subtype,
              CParserTool::GetString(msgmap, "Bond_Subtype"));
    msgmap.getDouble("Issue_Amount", ssbondinfor_unit.m_Issue_Amount);
    msgmap.GetInt32("Maturity_Term", ssbondinfor_unit.m_Maturity_Term);
    FIELDCOPY(ssbondinfor_unit.m_Maturity_Term_New,
              CParserTool::GetString(msgmap, "Maturity_Term_New"));
    FIELDCOPY(ssbondinfor_unit.m_Term_Unit,
              CParserTool::GetString(msgmap, "Term_Unit"));
    msgmap.GetUInt32("Maturity_Date", ssbondinfor_unit.m_Maturity_Date);
    FIELDCOPY(ssbondinfor_unit.m_Option_Type,
              CParserTool::GetString(msgmap, "Option_Type"));
    msgmap.GetInt32("Redemption_No", ssbondinfor_unit.m_Redemption_No);
    FIELDCOPY(ssbondinfor_unit.m_Redemption_Str,
              CParserTool::GetString(msgmap, "Redemption_Str"));
    FIELDCOPY(ssbondinfor_unit.m_Underwriter_Name,
              CParserTool::GetString(msgmap, "Underwriter_Name"));
    FIELDCOPY(ssbondinfor_unit.m_Rating_Augment,
              CParserTool::GetString(msgmap, "Rating_Augment"));
    FIELDCOPY(ssbondinfor_unit.m_WarranterName,
              CParserTool::GetString(msgmap, "WarranterName"));
    FIELDCOPY(ssbondinfor_unit.m_Coupon_Type,
              CParserTool::GetString(msgmap, "Coupon_Type"));
    msgmap.GetInt32("Fixing_MA_Days", ssbondinfor_unit.m_Fixing_MA_Days);
    FIELDCOPY(ssbondinfor_unit.m_FRN_Index_ID,
              CParserTool::GetString(msgmap, "FRN_Index_ID"));
    msgmap.GetFloat("Index_Rate", ssbondinfor_unit.m_Index_Rate);
    msgmap.GetFloat("Coupon_Rate_Spread",
                    ssbondinfor_unit.m_Coupon_Rate_Spread);
    msgmap.getFloat("Coupon_Rate_Current",
                    ssbondinfor_unit.m_Coupon_Rate_Current);
    msgmap.getFloat("Issue_Price", ssbondinfor_unit.m_Issue_Price);
    msgmap.getFloat("Issue_Rate", ssbondinfor_unit.m_Issue_Rate);
    FIELDCOPY(ssbondinfor_unit.m_Coupon_Frequency,
              CParserTool::GetString(msgmap, "Coupon_Frequency"));
    FIELDCOPY(ssbondinfor_unit.m_Compound_Frequency,
              CParserTool::GetString(msgmap, "Compound_Frequency"));
    msgmap.GetUInt32("Issue_Start_Date", ssbondinfor_unit.m_Issue_Start_Date);
    msgmap.GetUInt32("Auction_Date_Start",
                     ssbondinfor_unit.m_Auction_Date_Start);
    msgmap.GetUInt32("Interest_Start_Date",
                     ssbondinfor_unit.m_Interest_Start_Date);
    msgmap.GetUInt32("Payment_Date", ssbondinfor_unit.m_Payment_Date);
    msgmap.GetUInt32("Listed_Date", ssbondinfor_unit.m_Listed_Date);
    msgmap.GetUInt32("Next_coupon_Date", ssbondinfor_unit.m_Next_coupon_Date);
    msgmap.GetUInt32("Option_date", ssbondinfor_unit.m_Option_date);
    msgmap.GetUInt32("Delisted_Date", ssbondinfor_unit.m_Delisted_Date);

    // 2.0英文版字段

    FIELDCOPY(ssbondinfor_unit.m_Short_Name_En,
              CParserTool::GetString(msgmap, "Short_Name_En"));
    FIELDCOPY(ssbondinfor_unit.m_Full_Name_En,
              CParserTool::GetString(msgmap, "Full_Name_En"));
    FIELDCOPY(ssbondinfor_unit.m_Issuer_Rating_Dept_En,
              CParserTool::GetString(msgmap, "Issuer_Rating_Dept_En"));
    FIELDCOPY(ssbondinfor_unit.m_Rating_Current_Dept_En,
              CParserTool::GetString(msgmap, "Rating_Current_Dept_En"));
    FIELDCOPY(ssbondinfor_unit.m_Underwriter_Name_En,
              CParserTool::GetString(msgmap, "Underwriter_Name_En"));

    ProtoList submsglist;
    if (msgmap.getList("ListedMarket", submsglist)) {
      xBondSSListMarket_c market_unit;
      for (ProtoList::const_iterator market_it = submsglist.begin();
           market_it != submsglist.end(); ++market_it) {
        if (market_it->Type != ProtoValue::VAR_MAP) continue;
        const ProtoMap& submsg = *market_it;
        memset(&market_unit, 0, sizeof(xBondSSListMarket_c));

        FIELDCOPY(market_unit.m_Listed_Market,
                  CParserTool::GetString(submsg, "Listed_Market"));
        FIELDCOPY(market_unit.m_Bond_ID,
                  CParserTool::GetString(submsg, "Bond_ID"));
        FIELDCOPY(market_unit.m_Short_Name,
                  CParserTool::GetString(submsg, "Short_Name"));
        submsg.GetFloat("Conversion_rate", market_unit.m_Conversion_rate);

        ssbondinfor_unit.m_ListedMarket.push_back(market_unit);
      }
    }

    submsglist.clear();
    if (msgmap.GetList("BondRateList", submsglist)) {
      xBondRatingUnit_c rating_unit;
      for (ProtoList::const_iterator rating_it = submsglist.begin();
           rating_it != submsglist.end(); ++rating_it) {
        if (rating_it->Type != ProtoValue::VAR_MAP) continue;
        const ProtoMap& submsg = *rating_it;
        memset(&rating_unit, 0, sizeof(xBondRatingUnit_c));

        submsg.GetUInt32("Rating_Date", rating_unit.m_Rating_Date);
        FIELDCOPY(rating_unit.m_Rating,
                  CParserTool::GetString(submsg, "Rating"));
        FIELDCOPY(rating_unit.m_Rating_Institution_Name,
                  CParserTool::GetString(submsg, "Rating_Institution_Name"));
        FIELDCOPY(rating_unit.m_OutLook,
                  CParserTool::GetString(submsg, "OutLook"));
        FIELDCOPY(rating_unit.m_Type, CParserTool::GetString(submsg, "Type"));
        FIELDCOPY(rating_unit.m_Rating_Institution_Code,
                  CParserTool::GetString(submsg, "Rating_Institution_Code"));

        ssbondinfor_unit.m_BondRateList.push_back(rating_unit);
      }
    }

    submsglist.clear();
    if (msgmap.GetList("VenderList", submsglist)) {
      xInstitutionUnit_c inst_unit;
      for (ProtoList::const_iterator inst_it = submsglist.begin();
           inst_it != submsglist.end(); ++inst_it) {
        if (inst_it->Type != ProtoValue::VAR_MAP) continue;
        const ProtoMap& submsg = *inst_it;
        memset(&inst_unit, 0, sizeof(xInstitutionUnit_c));

        FIELDCOPY(inst_unit.m_Full_Name_C,
                  CParserTool::GetString(submsg, "Full_Name_C"));

        ssbondinfor_unit.m_VenderList.push_back(inst_unit);
      }
    }

    ptr->m_List.push_back(ssbondinfor_unit);
  }

  return ptr;
}

void* qbbond::extractBondIssuerInfo(const ProtoMessage& msg) {
  xBondIssuerInfo_c* ptr = new xBondIssuerInfo_c();

  FIELDCOPY(ptr->m_BondKey, CParserTool::GetString(msg, "BondKey"));
  FIELDCOPY(ptr->m_Listed_Market, CParserTool::GetString(msg, "Listed_Market"));
  FIELDCOPY(ptr->m_Full_Name_C, CParserTool::GetString(msg, "Full_Name_C"));
  FIELDCOPY(ptr->m_Full_Name_En, CParserTool::GetString(msg, "Full_Name_En"));
  FIELDCOPY(ptr->m_Short_Name_C, CParserTool::GetString(msg, "Short_Name_C"));
  FIELDCOPY(ptr->m_Short_Name_En, CParserTool::GetString(msg, "Short_Name_En"));
  FIELDCOPY(ptr->m_Institution_Type,
            CParserTool::GetString(msg, "Institution_Type"));
  FIELDCOPY(ptr->m_Org_Type, CParserTool::GetString(msg, "Org_Type"));
  FIELDCOPY(ptr->m_SW_Sector, CParserTool::GetString(msg, "SW_Sector"));
  FIELDCOPY(ptr->m_SW_Subsector, CParserTool::GetString(msg, "SW_Subsector"));
  FIELDCOPY(ptr->m_Province, CParserTool::GetString(msg, "Province"));
  FIELDCOPY(ptr->m_City, CParserTool::GetString(msg, "City"));
  FIELDCOPY(ptr->m_Stockholder_name,
            CParserTool::GetString(msg, "Stockholder_name"));
  FIELDCOPY(ptr->m_Stockholder_nameEn,
            CParserTool::GetString(msg, "Stockholder_nameEn"));
  FIELDCOPY(ptr->m_Stockholder_type,
            CParserTool::GetString(msg, "Stockholder_type"));
  FIELDCOPY(ptr->m_Stockholding_percentage,
            CParserTool::GetString(msg, "Stockholding_percentage"));
  msg.getDouble("Regd_Capital", ptr->m_Regd_Capital);
  FIELDCOPY(ptr->m_Regd_Capital_Currency,
            CParserTool::GetString(msg, "Regd_Capital_Currency"));
  FIELDCOPY(ptr->m_Actual_Controller,
            CParserTool::GetString(msg, "Actual_Controller"));
  FIELDCOPY(ptr->m_Actual_ControllerEn,
            CParserTool::GetString(msg, "Actual_ControllerEn"));
  FIELDCOPY(ptr->m_Actual_Controller_type,
            CParserTool::GetString(msg, "Actual_Controller_type"));
  FIELDCOPY(ptr->m_Business_Scope,
            CParserTool::GetString(msg, "Business_Scope"));
  FIELDCOPY(ptr->m_IssuerCode, CParserTool::GetString(msg, "IssuerCode"));

  return ptr;
}

void* qbbond::extractQBMixedBestquoteCodec(const ProtoMessage& msg) {
  static const char* bondkey = "bk";
  static const char* listedmarket = "lm";
  static const char* messageSeq = "seq";
  static const char* contributorId = "cid";
  static const char* version = "ver";
  static const char* modifyTime = "mdt";

  static const char* bidQuoteStatus = "bQst";
  static const char* bidPrice = "bPrc";
  static const char* bidYield = "bYld";
  static const char* bidNetPrice = "bNp";
  static const char* bidFullPrice = "bFp";
  static const char* bidVolumn = "bVol";
  static const char* bidInterpret = "bIntp";
  static const char* bidQuoteType = "bQtp";
  static const char* bidBarginFlag = "bBar";
  static const char* bidRelationFlag = "bRel";
  static const char* bidExercise = "bExec";
  static const char* bidCompanyId = "bCid";

  static const char* ofrQuoteStatus = "oQst";
  static const char* ofrPrice = "oPrc";
  static const char* ofrYield = "oYld";
  static const char* ofrNetPrice = "oNp";
  static const char* ofrFullPrice = "oFp";
  static const char* ofrVolumn = "oVol";
  static const char* ofrInterpret = "oIntp";
  static const char* ofrQuoteType = "oQtp";
  static const char* ofrBarginFlag = "oBar";
  static const char* ofrRelationFlag = "oRel";
  static const char* ofrExercise = "oExec";
  static const char* ofrCompanyId = "oCid";

  xQBMixedBestQuoteAck_c* ptr = new xQBMixedBestQuoteAck_c();
  qb::base::msg::Raw raw;
  if (!msg.GetRaw("list", raw)) return nullptr;

  qb::proto::VariantTableDecoder subList;
  if (!subList.decode((const char*)raw.Data, raw.Length)) return nullptr;

  xQBMixedBestQuoteUnit_c unit;
  std::string sTemp;
  for (auto itr = subList.begin(); itr != subList.end(); ++itr) {
    const qb::proto::VariantRecord* msgmap = *itr;

    memset(&unit, 0, sizeof(xQBMixedBestQuoteUnit_c));
    FIELDCOPY(unit.m_bondkey, CParserTool::GetString(msgmap, bondkey));
    FIELDCOPY(unit.m_listedmarket,
              CParserTool::GetString(msgmap, listedmarket));
    FIELDCOPY(unit.m_messageSeq, CParserTool::GetString(msgmap, messageSeq));
    FIELDCOPY(unit.m_contributorId,
              CParserTool::GetString(msgmap, contributorId));

    int64_t ver = 0;
    msgmap->getInt64(version, ver);
    unit.m_version = ver;

    int64_t t64 = 0;
    msgmap->getInt64(modifyTime, t64);
    unit.m_modifyTime = t64;

    FIELDCOPY(unit.m_bidQuoteStatus,
              CParserTool::GetString(msgmap, bidQuoteStatus));
    FIELDCOPY(unit.m_bidPrice, CParserTool::GetString(msgmap, bidPrice));
    FIELDCOPY(unit.m_bidYield, CParserTool::GetString(msgmap, bidYield));
    FIELDCOPY(unit.m_bidNetPrice, CParserTool::GetString(msgmap, bidNetPrice));
    FIELDCOPY(unit.m_bidFullPrice,
              CParserTool::GetString(msgmap, bidFullPrice));
    FIELDCOPY(unit.m_bidVolumn, CParserTool::GetString(msgmap, bidVolumn));
    FIELDCOPY(unit.m_bidInterpret,
              CParserTool::GetString(msgmap, bidInterpret));
    FIELDCOPY(unit.m_bidQuoteType,
              CParserTool::GetString(msgmap, bidQuoteType));
    FIELDCOPY(unit.m_bidBarginFlag,
              CParserTool::GetString(msgmap, bidBarginFlag));
    FIELDCOPY(unit.m_bidRelationFlag,
              CParserTool::GetString(msgmap, bidRelationFlag));
    FIELDCOPY(unit.m_bidExercise, CParserTool::GetString(msgmap, bidExercise));
    FIELDCOPY(unit.m_bidCompanyId,
              CParserTool::GetString(msgmap, bidCompanyId));

    FIELDCOPY(unit.m_ofrQuoteStatus,
              CParserTool::GetString(msgmap, ofrQuoteStatus));
    FIELDCOPY(unit.m_ofrPrice, CParserTool::GetString(msgmap, ofrPrice));
    FIELDCOPY(unit.m_ofrYield, CParserTool::GetString(msgmap, ofrYield));
    FIELDCOPY(unit.m_ofrNetPrice, CParserTool::GetString(msgmap, ofrNetPrice));
    FIELDCOPY(unit.m_ofrFullPrice,
              CParserTool::GetString(msgmap, ofrFullPrice));
    FIELDCOPY(unit.m_ofrVolumn, CParserTool::GetString(msgmap, ofrVolumn));
    FIELDCOPY(unit.m_ofrInterpret,
              CParserTool::GetString(msgmap, ofrInterpret));
    FIELDCOPY(unit.m_ofrQuoteType,
              CParserTool::GetString(msgmap, ofrQuoteType));
    FIELDCOPY(unit.m_ofrBarginFlag,
              CParserTool::GetString(msgmap, ofrBarginFlag));
    FIELDCOPY(unit.m_ofrRelationFlag,
              CParserTool::GetString(msgmap, ofrRelationFlag));
    FIELDCOPY(unit.m_ofrExercise, CParserTool::GetString(msgmap, ofrExercise));
    FIELDCOPY(unit.m_ofrCompanyId,
              CParserTool::GetString(msgmap, ofrCompanyId));

    ptr->m_list.push_back(unit);
  }

  return ptr;
}

void* qbbond::extractPanoramicMarketStreamDealAck(const ProtoMessage& msg) {
  ProtoList msgList;
  if (!msg.getList("List", msgList)) return nullptr;

  xQBPanoramicMarketStreamDealAck* ptr = new xQBPanoramicMarketStreamDealAck;
  xQBPanoramicMarketStreamUnit unit;
  for (ProtoList::const_iterator it = msgList.begin(); it != msgList.end();
       ++it) {
    if (it->Type != ProtoValue::VAR_MAP) continue;
    memset(&unit, 0, sizeof(unit));
    const ProtoMap& msgmap = *it;
    msgmap.GetInt32("indexID", unit.m_indexID);
    CParserTool::MessageGetTime(msgmap, "updateTime", unit.m_updateTime);
    FIELDCOPY(unit.m_bondCode, CParserTool::GetString(msgmap, "bondCode"));
    FIELDCOPY(unit.m_bondkey, CParserTool::GetString(msgmap, "bondkey"));
    FIELDCOPY(unit.m_listedmarket,
              CParserTool::GetString(msgmap, "listedmarket"));
    FIELDCOPY(unit.m_price, CParserTool::GetString(msgmap, "price"));
    FIELDCOPY(unit.m_cleanPrice, CParserTool::GetString(msgmap, "cleanPrice"));
    FIELDCOPY(unit.m_yield, CParserTool::GetString(msgmap, "yield"));
    FIELDCOPY(unit.m_id, CParserTool::GetString(msgmap, "id"));
    FIELDCOPY(unit.m_dealStatus, CParserTool::GetString(msgmap, "dealStatus"));
    FIELDCOPY(unit.m_preCloseYield,
              CParserTool::GetString(msgmap, "lastCloseYield"));
    FIELDCOPY(unit.m_preClosecleanPrice,
              CParserTool::GetString(msgmap, "lastClosecleanPrice"));
    FIELDCOPY(unit.m_withinPeriodDeal,
              CParserTool::GetString(msgmap, "withinPeriodDeal"));
    FIELDCOPY(unit.m_listedFirstDeal,
              CParserTool::GetString(msgmap, "listedFirstDeal"));
    FIELDCOPY(unit.m_companyId, CParserTool::GetString(msgmap, "companyId"));
    FIELDCOPY(unit.m_preAdv, CParserTool::GetString(msgmap, "preAdv"));

    FIELDCOPY(unit.m_operate, CParserTool::GetString(msgmap, "operate"));
    FIELDCOPY(unit.m_quotetype, CParserTool::GetString(msgmap, "quotetype"));
    FIELDCOPY(unit.m_exercise, CParserTool::GetString(msgmap, "exercise"));
    msgmap.GetInt32("Redemption_No", unit.m_Redemption_No);
    ptr->m_List.push_back(unit);
  }
  return ptr;
}

void* qbbond::extractQBABBondRecommendPriceAck(const ProtoMessage& msg) {
  qb::base::msg::Raw raw;
  if (!msg.GetRaw("list", raw)) return nullptr;

  qb::proto::VariantTableDecoder msglist;
  if (!msglist.decode((const char*)raw.Data, raw.Length)) return nullptr;

  xQBAbBondRecommendPriceAck_t* ptr = new xQBAbBondRecommendPriceAck_t();
  xQBAbBondRecommendPriceUnit unit;
  for (auto it = msglist.begin(); it != msglist.end(); ++it) {
    const qb::proto::VariantRecord* msgmap = *it;
    memset(&unit, 0, sizeof(xQBAbBondRecommendPriceUnit));
    FIELDCOPY(unit.m_bond_key, CParserTool::GetString(msgmap, "bk"));
    FIELDCOPY(unit.m_listed_market, CParserTool::GetString(msgmap, "lm"));
    FIELDCOPY(unit.m_price, CParserTool::GetString(msgmap, "pri"));

    ptr->m_list.push_back(unit);
  }
  return ptr;
}
